version check infrastructure
This commit is contained in:
parent
6a9a7dee55
commit
c7a0626c69
@ -115,6 +115,8 @@ get_dock_menu(id self UNUSED, SEL _cmd UNUSED, NSApplication *sender UNUSED) {
|
||||
return dockMenu;
|
||||
}
|
||||
|
||||
static PyObject *notification_activated_callback = NULL;
|
||||
|
||||
@interface NotificationDelegate : NSObject <NSUserNotificationCenterDelegate>
|
||||
@end
|
||||
|
||||
@ -133,13 +135,19 @@ get_dock_menu(id self UNUSED, SEL _cmd UNUSED, NSApplication *sender UNUSED) {
|
||||
- (void) userNotificationCenter:(NSUserNotificationCenter *)center
|
||||
didActivateNotification:(NSUserNotification *)notification {
|
||||
(void)(center); (void)(notification);
|
||||
if (notification_activated_callback) {
|
||||
PyObject *ret = PyObject_CallFunction(notification_activated_callback, "z",
|
||||
notification.identifier ? [notification.identifier UTF8String] : NULL);
|
||||
if (ret == NULL) PyErr_Print();
|
||||
else Py_DECREF(ret);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
static PyObject*
|
||||
cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
char *title = NULL, *subtitle = NULL, *message = NULL, *path_to_image = NULL;
|
||||
if (!PyArg_ParseTuple(args, "ssz|z", &title, &message, &path_to_image, &subtitle)) return NULL;
|
||||
char *identifier = NULL, *title = NULL, *subtitle = NULL, *message = NULL, *path_to_image = NULL;
|
||||
if (!PyArg_ParseTuple(args, "zssz|z", &identifier, &title, &message, &path_to_image, &subtitle)) return NULL;
|
||||
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
||||
if (!center) {PyErr_SetString(PyExc_RuntimeError, "Failed to get the user notification center"); return NULL; }
|
||||
if (!center.delegate) center.delegate = [[NotificationDelegate alloc] init];
|
||||
@ -151,6 +159,7 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
img = [[NSImage alloc] initWithContentsOfURL:url];
|
||||
[url release]; [p release];
|
||||
}
|
||||
n.identifier = identifier ? [NSString stringWithUTF8String:identifier] : nil;
|
||||
n.title = title ? [NSString stringWithUTF8String:title] : nil;
|
||||
n.subtitle = subtitle ? [NSString stringWithUTF8String:subtitle] : nil;
|
||||
n.informativeText = message ? [NSString stringWithUTF8String:message] : nil;
|
||||
@ -159,6 +168,7 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
[n setValue:@(false) forKey:@"_identityImageHasBorder"];
|
||||
}
|
||||
[center deliverNotification:n];
|
||||
if (n.identifier) { [n.identifier release]; n.identifier = nil; }
|
||||
if (n.title) { [n.title release]; n.title = nil; }
|
||||
if (n.subtitle) { [n.subtitle release]; n.subtitle = nil; }
|
||||
if (n.informativeText) { [n.informativeText release]; n.informativeText = nil; }
|
||||
@ -167,6 +177,41 @@ cocoa_send_notification(PyObject *self UNUSED, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
SIGTERM_handler(int signum UNUSED) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
call_timer_callback(PyObject *timer_callback) {
|
||||
PyObject *ret = PyObject_CallObject(timer_callback, NULL);
|
||||
if (ret == NULL) PyErr_Print();
|
||||
else Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
cocoa_run_notification_loop(PyObject *self UNUSED, PyObject *args) {
|
||||
PyObject *timer_callback;
|
||||
double timeout;
|
||||
if (!PyArg_ParseTuple(args, "OOd", ¬ification_activated_callback, &timer_callback, &timeout)) return NULL;
|
||||
signal(SIGTERM, SIGTERM_handler);
|
||||
signal(SIGINT, SIGTERM_handler);
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
NSApplication * application = [NSApplication sharedApplication];
|
||||
// prevent icon in dock
|
||||
[application setActivationPolicy:NSApplicationActivationPolicyAccessory];
|
||||
// timer will fire after timeout, so fire it once at the start
|
||||
call_timer_callback(timer_callback);
|
||||
[NSTimer scheduledTimerWithTimeInterval:timeout
|
||||
repeats:YES
|
||||
block:^(NSTimer *timer UNUSED) {
|
||||
call_timer_callback(timer_callback);
|
||||
}];
|
||||
[application run];
|
||||
[pool drain];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cocoa_create_global_menu(void) {
|
||||
NSString* app_name = find_app_name();
|
||||
@ -376,6 +421,7 @@ static PyMethodDef module_methods[] = {
|
||||
{"cocoa_get_lang", (PyCFunction)cocoa_get_lang, METH_NOARGS, ""},
|
||||
{"cocoa_set_new_window_trigger", (PyCFunction)cocoa_set_new_window_trigger, METH_VARARGS, ""},
|
||||
{"cocoa_send_notification", (PyCFunction)cocoa_send_notification, METH_VARARGS, ""},
|
||||
{"cocoa_run_notification_loop", (PyCFunction)cocoa_run_notification_loop, METH_VARARGS, ""},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
@ -3,20 +3,76 @@
|
||||
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from urllib.request import urlopen
|
||||
|
||||
from .constants import is_macos, logo_png_file
|
||||
from .constants import cache_dir, is_macos, logo_png_file, version
|
||||
from .utils import open_url
|
||||
|
||||
CHANGELOG_URL = 'https://sw.kovidgoyal.net/kitty/changelog.html'
|
||||
RELEASED_VERSION_URL = 'https://sw.kovidgoyal.net/kitty/current-version.txt'
|
||||
CHECK_INTERVAL = 24 * 60 * 60
|
||||
|
||||
|
||||
def version_notification_log():
|
||||
return os.path.join(cache_dir(), 'new-version-notifications.txt')
|
||||
|
||||
|
||||
def notify_new_version(version):
|
||||
notify('kitty update available!', 'kitty version {} released'.format('.'.join(map(str, version))))
|
||||
|
||||
|
||||
def get_released_version():
|
||||
try:
|
||||
raw = urlopen(RELEASED_VERSION_URL).read().decode('utf-8').strip()
|
||||
except Exception:
|
||||
raw = '0.0.0'
|
||||
return tuple(map(int, raw.split('.')))
|
||||
|
||||
|
||||
notified_versions = set()
|
||||
|
||||
|
||||
def save_notification(version):
|
||||
notified_versions.add(version)
|
||||
version = '.'.join(map(str, version))
|
||||
with open(version_notification_log(), 'a') as f:
|
||||
print(version, file=f)
|
||||
|
||||
|
||||
def already_notified(version):
|
||||
if not hasattr(already_notified, 'read_cache'):
|
||||
already_notified.read_cache = True
|
||||
with open(version_notification_log()) as f:
|
||||
for line in f:
|
||||
notified_versions.add(tuple(map(int, line.strip().split('.'))))
|
||||
return tuple(version) in notified_versions
|
||||
|
||||
|
||||
if is_macos:
|
||||
from .fast_data_types import cocoa_send_notification
|
||||
from .fast_data_types import cocoa_send_notification, cocoa_run_notification_loop
|
||||
|
||||
def notify(title, body, timeout=5000, application='kitty', icon=True):
|
||||
def notify(title, body, timeout=5000, application='kitty', icon=True, identifier=None):
|
||||
if icon is True:
|
||||
icon = None
|
||||
cocoa_send_notification(title, body, icon)
|
||||
cocoa_send_notification(identifier, title, body, icon)
|
||||
|
||||
def notification_activated(notification_identifier):
|
||||
open_url(CHANGELOG_URL)
|
||||
|
||||
def do_check():
|
||||
new_version = get_released_version()
|
||||
if new_version > version and not already_notified(new_version):
|
||||
save_notification(new_version)
|
||||
notify_new_version(new_version)
|
||||
|
||||
def update_check():
|
||||
cocoa_run_notification_loop(notification_activated, do_check, CHECK_INTERVAL)
|
||||
|
||||
else:
|
||||
def notify(title, body, timeout=5000, application='kitty', icon=True):
|
||||
def notify(title, body, timeout=5000, application='kitty', icon=True, identifier=None):
|
||||
cmd = ['notify-send', '-t', str(timeout), '-a', application]
|
||||
if icon is True:
|
||||
icon = logo_png_file
|
||||
@ -24,3 +80,11 @@ else:
|
||||
cmd.extend(['-i', icon])
|
||||
subprocess.Popen(
|
||||
cmd + [title, body], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
|
||||
|
||||
def update_check():
|
||||
while True:
|
||||
new_version = get_released_version()
|
||||
if new_version > version and not already_notified(new_version):
|
||||
save_notification(new_version)
|
||||
notify_new_version(new_version)
|
||||
time.sleep(CHECK_INTERVAL)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user