Uniquely identify active window on OS X - objective-c

I’m trying to patch an application that resizes windows using the accessibility API.
I need to maintain a dictionary with the previous sizes of windows. The key needs to identify the currently active window. At the moment, this active window is retrieved via NSAccessibilityFocusedWindowAttribute upon the press of a hotkey.
However, every time this method is called, the returned AXUIElementRef which identifies the window is different! This of course means that I cannot use it as a dictionary key – the dictionary won’t find the corresponding entry.
The following code reproduces the problem:
-(IBAction)testWindowIdentification:(id)sender{
AXUIElementRef focusedApp;
AXUIElementRef focusedWindow;
AXUIElementCopyAttributeValue(_systemWideElement,
(CFStringRef) kAXFocusedApplicationAttribute,
(CFTypeRef*) &focusedApp);
AXUIElementCopyAttributeValue((AXUIElementRef) focusedApp,
(CFStringRef) NSAccessibilityFocusedWindowAttribute,
(CFTypeRef*) &focusedWindow);
CFShow(focusedWindow);
}
_systemWideElement has been initialised in the init method using a call to AXUIElementCreateSystemWide().
The CFShow statement clearly shows different IDs every time the method is called (even though the same window is active), which is useless for me:
<AXUIElement 0x47e850> {pid=42463}
<AXUIElement 0x47e890> {pid=42463}
<AXUIElement 0x47e2c0> {pid=42463}
…
The documentation on AXUIElement shows no method that retrieves a unique attribute for the UI element, and neither does that of the NSAccessibility protocol.
The unique PID is not enough for me, since a process can have multiple windows.
How can I retrieve some unique identifier of the active window in Cocoa?
(By the way, the real code is checking the return codes in the above calls; there is no error, the calls succeed.)

Rob Keniger has the right strategy with his answer here. The only thing missing from this answer (and indeed, the reason for the bounty placement) is a workable implementation that takes the current active window and translates it into a unique key suitable for indexing in the context of the current working application.
Rob's solution sketches this out through use of the CGWindowID given in the context of Quartz Window Services. It is, of course, strongly implied that this window reference is only useful for your current application.
Getting this window reference is tricky, because no strong guarantees exist between the Accessibility API and Quartz Window Services. However, you can work around this in the following ways:
Use extern "C" AXError _AXUIElementGetWindow(AXUIElementRef, CGWindowID* out);, as documented here. This isn't guaranteed to work, but it works as a ground-floor test to get things started if it works in your version of OSX.
Get the CGWindowID directly, using, for example, HIWindowGetCGWindowID(). More details about selecting the active window and extracting the ID can be found in the reference manual for the Carbon Window Manager (warning: large PDF).
Catalog your CGWindowID set using something like CGWindowListCreateDescriptionFromArray, exactly as Rob suggested. The goal here is then to find some scheme for bridging the Accessibility API and Quartz, but this is conceivable by utilizing, for example, a callback bound to the context of your current active window. I honestly don't know an optimal example of this that's properly future-proofed, however.
Of the options, I recommend going with 2. for your current needs, if you're unable to create some other decorator for your windows to uniquely identify them. It's currently defined in the legacy code base, but it will do what you desire.
Best of luck with your application.

I think you might be able to use the Quartz Window Services functions, specifically CGWindowListCreateDescriptionFromArray to enumerate the currently active windows in a particular app.
This call is lower-level than AppKit and isn't going to tell you which is the active window, but it will give you window IDs that are unique for the current user session. It's not a great solution, but you could compare the window bounds information with what you receive from the accessibility APIs to associate windows with their real IDs.

Related

Check original language of repository objects at creation?

In our company, repository objects must be created with original language EN.
Is there a way to check the logon language in case of creating a new object in the ABAP repository?
Desired behaviour:
SE80 - Create program/class/data element/table/....
==> user exit/badi checks the logon language. When it is not 'EN', the creation will be refused.
regards,
Umar Abdullah
I know there is a exit for this but I haven't remember exact name. You can use general purpose for finding exit. Go to SE24 and open CL_EXITHANDLER class, find GET_INSTANCE method and add break point. Then start creating item, it will pause on debugger multiple times, try to find suitable one.
As #mkysoft suggested, you may implement a check in the BAdI CTS_REQUEST_CHECK, method CHECK_BEFORE_ADD_OBJECTS, which is invoked when the object is about to be attached to a transport request. Raise the exception CANCEL to make the attachment fail (and so the object is not created too).
EDIT: sorry, ignore my answer, "this method is NOT released for Customer usage" as said in note 2150125 - Method CHECK_BEFORE_ADD_OBJECTS not triggered
DISCLAIMER: THE METHOD DESCRIBED HERE IS ABSOLUTELY NOT RECOMMENDED.
As correctly pointed out by the other members there is no standard and customer-exposed method to achieve your requirement, but if you absolutely must enable this check during creation you can use the below method. As well as the previously offered to you, it also involves modification of SAP standard.
There is a system BAdi CTS_TADIR_SUBSCREEN that is located inside enhancement point CTS_ES_TADIR_POPUP. They are SAP internal and not released for customer usage, so do this at your own risk.
Implementation procedure:
Step 0. First thing you need to change is a SAP internal usage flag, for which you need Object Access key which can be obtained from SAP or from SAP partner that made the implementation in your org. In virgin state this BAdi throws the error if you try to implement it
So hereinafter we assume that you already ticked off this checkbox in BAdi settings
Step 1.
In order to implement the BAdi one need to implement enhancement spot prior to that. This is the most complicated part, because despite we disabled internality flag the SAP-namespaced enhancements must be stored only in SAP-namespaced objects. By SAP namespace I mean non-Z, non-Y and non-T (Test). This means to implement this enhancement, besides modifying the enhancement definition, one need to create, for example, CTS_ES_TADIR named enh.impl., and save it to non-Z package, which you also need to create. Your enhancement implementations selector should look somehow like this
On the above screen only the second will work, all the rest Z will not.
Every non-Z object need Object Access Key, remember? Too bad. But just to show the proof-of-concept, I will proceed.
Step 2. After you created the enh. implementation in SAP-namespace it will propose you to create the BAdi implementation. The same principle applies here: only SAP-namespaced container for SAP-namespaced objects, hence CTS_TADIR_SUBSCREEN should have implementing class for example CL_TADIR_SUBSCREEN. During the creation of enhancement you will see many warnings
but finally you should have something like this, where all system-named objects are created and the enhancement/BAdi is activated.
Step 3. In order to get the BAdi working we need to enable this subscreen processing
during the playing with enhancement I found out that BAdi class is not being triggered standalone, without screen events not enhanced, so to make it work you need to touch a screen enhancement for screen 100
If you do not wanna modify screen elements logic, just put the dummy enhancement in SHOW_TADIR dialog module in the end of the include LSTRDO18
PROCESS BEFORE OUTPUT.
MODULE SHOW_TADIR. "<-- create the dummy enhancement here
CALL SUBSCREEN subs_info INCLUDING gv_badi_prog gv_badi_dynnr.
for example declaration statement like I did
Step 4. Activate your created BAdi class and put the necessary logic there. I wasn't able to trigger method GET_DATA_FROM_SCREEN, but PUT_DATA_TO_SCREEN worked fine
If we put this simple processing for your requirement
METHOD cts_if_tadir_subscreen~get_data_from_screen.
IF object_data-l_mstlang <> 'E'.
MESSAGE 'Objects in non-English languages are not allowed!' TYPE 'A'.
ENDIF.
ENDMETHOD.
it will not allow creating objects in languages other than English.
The check in method get_data_from_screen is being done before showing the screen so language is determined from system logon settings. If to play more with this BAdi, I suppose the method GET_DATA_FROM_SCREEN can also be enabled, which will make it possible to check user input, i.e. the case when the user gonna change the default language.

Check if a process is a windowed process in OSX

Given the PID of a process, how can I check if it's a windowed process? I am looking for a solution on OSX.
Objective-C/ C solutions are wanted.
I am on OSX Mountain Lion.
I am defining a windowed process as a process that can be seen when the "Windowed Processes" tab is selected in activity monitor. http://cl.ly/FeXR
[NSWorkspace runningApplications]
This returns all the user applications in a NSArray as instances of NSRunningApplication which has a property processIdentifier.
Or you can use runningApplicationWithProcessIdentifier: directly to get the application with a specified PID.
Here is the sample code: http://developer.apple.com/library/Mac/#samplecode/AppList/Introduction/Intro.html
Through the activationPolicy property of the NSRunningApplication you could get the Windowed state. I modified the AppList code to make it show only the windowed applications as shown below. This matches what the activity monitor shows.
In particular, you are looking for the NSApplicationActivationPolicyRegular.
Note the restrictions however. This only works for user owned processes.
All other methods are deprecated and may not work in future. Methods like GetBSDProcessList and Carbon's GetProcessInformation are not recommended anymore.

Programmatically turn off an individual monitor

Is there an API or way to programmatically turn off an individual, external monitor via Objective-C on a Mac?
I'm looking to write a small menubar application that can control a secondary display (without a physical power button), but still keep the primary monitor in use.
Hunting around the API documentation, I can't seem to find anything, other then reading states. So hoping someone else might have an idea.
You can't "programmatically turn off an individual monitor", it's not physically possible. The most you can do is tell the OS to not use the monitor, but I don't think you can change system-wide settings like that, especially not at the level you're working on (Obj-C).
Looking at the Core Graphics API mentioned in #Halley's comment, try starting with the CGBeginDisplayConfiguration method and see if you can set a display configuration to your liking.
EDIT: Alternatively, you could also use CGDisplayCapture(displayID), which by default fills the captured display with black. You can then
call CGDisplayRelease(displayID) when you want to turn it back on.
It seems to be possible to sleep display so by I/O Kit:
https://web.archive.org/web/20161106204726/http://www.cocoabuilder.com/archive/cocoa/191807-sleep-display.html
http://explanatorygap.net/2009/01/31/a-screensaver-to-send-your-display-to-sleep/
But I am not sure whether it can control single monitors.

CLLocationManager initialization

I'm working on a web application that enables users to login, only at specific locations. I'm using CLLocationManager and I initialized and called startUpdatingLocation at AppDelegate -didFinishLaunchingWithOptions. My UIWebView is supposed to pull the location at initialization to determine whether user's within the specified locations. However, at the launch of my application, [locationManager location] is always null and updates after my UIWebView is initialized and displayed therefore already sending an error message to the user.
How do I make my locationManager update its location at initialization?
Sounds like you've coded the location stuff correctly. What you are missing (but have seen) is that the update most certainly does not happen instantaneously. You need to "gate" the rest of your UI's presentation (i.e. your webview) on the location information becoming available. There are a lot of ways to do this. A common tactic is to present a full-screen "HUD" or veil with some indicator to the user that the app is initializing or locating them (with an activity indicator, too, is always a nice touch.) Behind that (out of sight to the user) you can be waiting for the location result and then kickoff the appropriate UI update, and then drop the veil.
Any of that make sense or give you some ideas? I've done this plenty of times. Synchronizing async activities (like location updates) with real-time UI updates that make sense can be challenging, but isn't impossible. :-)
You will need to account for an initial nil value in your applications UI and wait for the first location update.
-location
Discussion
The value of this property is nil if no location data has
ever been retrieved.
It is a good idea to check the timestamp of the location that is
returned. If the receiver is currently gathering location data, but
the minimum distance filter is large, the returned location might be
relatively old. If it is, you can stop the receiver and start it again
to force an update
Also you should check out Region Monitoring since you would like for you users to only be able to login at specific locations.

Notifications in wxWidgets?

I'm working on a small application using C++/wxWidgets, where several parts of the GUI need to be updated based on e.g. received UDP datagrams. More specifically, a secondary thread tries to keep a list of available "clients" in the network (which may come and go away) and e.g. corresponding comboboxes in the UI need to be updated to reflect the changes.
The documentation mentions that for this kind of thing EVT_UPDATE_UI would be a good choice. As far as I can understand from the sparse documentation, this event is sent automatically by the system and provides some support for assisted UI change.
However, I'd feel more comfortable using a more direct approach, i.e. where e.g. a window object could register/subscribe to receive notifications (either events or callbacks) upon particular events and another part of the code is sending out these notifications when required. I could do this in C++ using my own code, however I guess if wxWidgets already supports something like that, I should make use of it. However I haven't found anything in that regards.
So, the question is: does wxWidgets support this kind of notification system (or similar alternatives) or would I be best served coding my own?
AFAIK there is nothing directly usable in wxWidgets, but doing it on your own seems easy.
What I would do:
Create a wxEvtHandler-descendent class to hold the list of available "clients" in the network. Let this class have a wxCriticalSection, and use a wxCriticalSectionLocker for that in all methods that add or delete "clients".
Create a worker thread class by inheriting wxThread to handle your UDP datagrams, using blocking calls. The thread should directly call methods of the client list object whenever a client has to be added or removed. In these methods update the list of clients, and ::wxPostEvent() an event to itself (this will execute the whole notification calls in the main GUI thread).
Handle the event in the client list class, and notify all listeners that the list of clients has changed. The observer pattern seems to me a good fit. You could either call a method of all registered listeners directly, or send a wxCommandEvent to them.
Have you tried calling Update() on the widget(s) that change? Once you update the contents of the combo box, call Update(), and the contents should update.