pyobjc & EventKit: trouble saving event (EKErrorDomain Code=11) - eventkit

I'm trying to save an event using pyobjc, but I get an EKErrorDomain Code 11 ("That event does not belong to that event store").
Here's what I have so far:
ek_store = EKEventStore.alloc().initWithAccessToEntityTypes_(0)
print(f'{ek_store=}')
my_cal_identifier = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
my_calendar = ek_store.calendarWithIdentifier_(my_cal_identifier)
print(f'{my_calendar.eventStore()=}') # obviously ek_store
event = EKEvent.alloc().init()
event.setEventStore_(ek_store)
print(f'{event.eventStore()=}') # ek_store, of course
event.setStartDate_(my_startDate) # NSDate, declared earlier
event.setEndDate_(my_endDate) # NSDate, declared earlier
event.setCalendar_(my_calendar)
event.setTitle_('My new event')
ek_store.saveEvent_span_error_(
event, 0, None
) # this throws the EKErrorDomain error
I'm utterly confused by the error message: the calendar as well as the event have the right event store set (I have only one defined anyway). What does this error mean in this context?
What am I missing?
In the documentation, it says "Create a new event with the init(eventStore:) method of the EKEvent class."
So maybe my problem stems from not understanding how to correctly create a new event with pyobjc (init does not allow arguments, so how can I pass on the event store?).

Related

How can i know if i drag a window of another application in a macOS application?

In Cocoa on the Mac, I'd like to detect when a window belonging to another app is moved, resized, or repainted. How can I do this?
You would need to use the Accessibility APIs, which are plain-C, located inside the ApplicationServices framework. For instance:
First you create an application object:
AXUIElementRef app = AXUIElementCreateApplication( targetApplicationProcessID );
Then you get the window from this. You can request the window list and enumerate, or you can get the frontmost window (look in AXAttributeConstants.h for all the attribute names you'd use).
AXUIElementRef frontWindow = NULL;
AXError err = AXUIElementCopyAttributeValue( app, kAXMainWindowAttribute, &frontWindow );
if ( err != kAXErrorSuccess )
// it failed -- maybe no main window (yet)
Now you can request notification via a C callback function when a property of this window changes. This is a four-step process:
First you need a callback function to receive the notifications:
void MyAXObserverCallback( AXObserverRef observer, AXUIElementRef element,
CFStringRef notificationName, void * contextData )
{
// handle the notification appropriately
// when using ObjC, your contextData might be an object, therefore you can do:
SomeObject * obj = (SomeObject *) contextData;
// now do something with obj
}
Next you need an AXObserverRef, which manages the callback routine. This requires the same process ID you used to create the 'app' element above:
AXObserverRef observer = NULL;
AXError err = AXObserverCreate( applicationProcessID, MyObserverCallback, &observer );
if ( err != kAXErrorSuccess )
// handle the error
Having got your observer, the next step is to request notification of certain things. See AXNotificationConstants.h for the full list, but for window changes you'll probably only need these two:
AXObserverAddNotification( observer, frontWindow, kAXMovedNotification, self );
AXObserverAddNotification( observer, frontWindow, kAXResizedNotification, self );
Note that the last parameter there is passing an assumed 'self' object as the contextData. This is not retained, so it's important to call AXObserverRemoveNotification when this object goes away.
Having got your observer and added notification requests, you now want to attach the observer to your runloop so you can be sent these notifications in an asynchronous manner (or indeed at all):
CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop],
AXObserverGetRunLoopSource(observer),
kCFRunLoopDefaultMode );
AXUIElementRefs are CoreFoundation-style objects, so you need to use CFRelease() to dispose of them cleanly. For cleanliness here, for example, you would use CFRelease(app) once you've obtained the frontWindow element, since you'll no longer need the app.
A note about Garbage-Collection: To keep an AXUIElementRef as a member variable, declare it like so:
__strong AXUIElementRef frontWindow;
This instructs the garbage collector to keep track of this reference to it. When assigning it, for compatibility with GC and non-GC, use this:
frontWindow = (AXUIElementRef) CFMakeCollectable( CFRetain(theElement) );
Further research turned up "Quartz Display Services"
The interesting function for my needs is CGRegisterScreenRefreshCallback.

Accessing calendars with EventKit on pyobjc (trouble passing entityType)

I'm aware this might be a dumb question, but I can't figure out how to translate this simple Swift statement (didn't find an Objective-C example) into pyobjc:
let calendars = EventStore.calendars(for entityType:.Events)
What I got so far (trying out different options):
from EventKit import EKEventStore
ek_event_store = EKEventStore.alloc().init()
default_cal = ek_event_store.defaultCalendarForNewReminders() # works, but not the calendar I wish to access
my_cal_identifier = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
my_cal = ek_event_store.calendar(my_cal_identifier)) # Error: 'EKEventStore' object has no attribute 'calendar'
calendars = ek_event_store.calendars() # value is None. I don't know how to pass it the entityType
So I guess my problem is not knowing
what the entityType is supposed to be (type? value?)
how to pass the entityType to the calendars function.
I figured it out (using the dir function on the event store object and on a calendar object)
from EventKit import EKEventStore
ek_event_store = EKEventStore.alloc().init()
my_cal_identifier = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
my_cal = ek_store.calendarWithIdentifier_(cal_tcv_intern_id)
all_my_calendars = ek_store.calendarsForEntityType_(0)
I didn't find the Event types in the documentation, but with trial and error, I figured it out:
0: calendar
1: reminder
So I also gained some better insight how pyobjc is working:
EventStore.calendars(for entityType:.Events) becomes EventStore.calendardsForEntityType(event_type).
I was also wondering why the "calendar" function could not be found, now I understand that it bacame calendarWithIdentifier in pyobjc.

ForEach in SwiftUI: Error "Missing argument for parameter #1 in call"

I'm still trying to create a calendar app and ran into another problem I wasn't able to find a solution for online.
Xcode throws the error "Missing argument for parameter #1 in call" in line 2 of my code sample. I used similar code at other places before, but I can't find the difference in this one.
Also this code worked before and started throwing this error after I moved some code to the new View DayViewEvent after getting the error "The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions", which I hoped to fix it and would be clean code anyway.
For reference: events is an optional array of EKEvents (hence the first if) and selectedDate is (obviously) a Date.
Any help is greatly appreciated!
if let events = events {
ForEach(events, id: \.self) { event in
if !event.isAllDay {
DayViewEvent(selectedDate: selectedDate, event: event)
}
}
}
The body func is called on every state change so needs to be as fast as possible thus the data needed should already be processed. So need to filter your events in a func or block, e.g. in onAppear:
struct EventsView: View {
#State var events = [Events]()
var body: some View {
ForEach(events, id: \.eventIdentifier) { event in
DayViewEvent(event: event)
}
.onAppear {
events = EventsDB.shared.events(isAllDay: false)
}
}
}
And by the way, since you are using id: \.self because event is a reference type you need to ensure when retrieving the events that the same event always returns the same instance and not a new instance. If unique instances are returned then you need to instead use an id that is a unique property, e.g. id: \.eventIdentifier.
Also you should know that the SwiftUI declarative syntax inside body is not like normal programming, the ifs and for loops all generate some very complex code, e.g. _ConditionalContent when an if is used, read up on it here: https://swiftwithmajid.com/2021/12/09/structural-identity-in-swiftui/ or watch Apple's WWDC video Demystify SwiftUI.

variable scope when dealing with event handlers

function World:draw()
--draw the tiles based on 2d int array
--draw the player
--draw the monsters
--show what you need to based on camera
self.map[0][0]=display.newImage("dirt_tile.png",i,j)
end
I can't access any of my world object's properties in there when I use the event handler:
Runtime:addEventListener("enterFrame",World.draw)
Is there a different kind of eventListener I can use, or is there a different way to instantiate the eventListener so the self-referencing context stays intact?
Here you go:
World = { count=0 }
function World:enterFrame()
self.count = self.count + 1
print("count = " .. self.count)
end
Runtime:addEventListener("enterFrame", World)
See this API reference page for details.
In you named your table local self = {}, then it may collide with the implicit self parameter.
The function World:draw() is just a Lua syntax sugar for World.draw = function(self). By working with self, you are using whatever first parameter the runtime event handler is passing to your function (judging from the API, it passes event, which you will get as self).
Try naming the table you want to access differently (like local this) and see if it works.

Prototype | keyup Event.stopObserving() not working when handler is bound to class

Here's my beef: I'm observing the document for a keyup and then calling a handler. The handler is calling a function of a class and is bound to the class's context. When the function is called and my conditionals are met, it's supposed to stop observing the handler. But its not.
Created a class, this is the function I'm calling on page:
look_for: function(key_combo) {
this.keys_array = key_combo.split("+");
this.match_key_handler = this.match_keys.bind(this);
document.observe('keyup', this.match_key_handler);
},
This calls the document to observe keyup and calls this.match_keys(). As you can see, it's assigned to a handler because the function needs to be bound. Below is the match_keys functions:
match_keys: function() {
// matching the keys here, blah blah
if(this.keys_matched) {
document.stopObserving('keyup',this.match_key_handler);
}
}
However, when the conditional is met, it doesn't stop observing! If I stopObserving all keyups on the document, it will unregister this function but I want it to only unregister the match_key_handler.
StackOverflow, help me out! Below is another post thats similar. Followed what was on the page but still no dice.
Stop Observing Events with JS Prototype not working with .bind(this)