summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extension.js260
-rwxr-xr-xgeoclue.js82
-rw-r--r--metadata.json3
-rw-r--r--place.js230
-rw-r--r--stylesheet.css8
5 files changed, 228 insertions, 355 deletions
diff --git a/extension.js b/extension.js
index 260aef7..bc89de1 100644
--- a/extension.js
+++ b/extension.js
@@ -1,53 +1,245 @@
-
+/* jshint moz: true, multistr: true */
+/* global imports */
+const Gio = imports.gi.Gio;
+const Mainloop = imports.mainloop;
+const GObject = imports.gi.GObject;
+const Lang = imports.lang;
const St = imports.gi.St;
const Main = imports.ui.main;
-const Tweener = imports.ui.tweener;
-let text, button;
+const AccuracyLevel = {
+ COUNTRY: 1,
+ CITY: 4,
+ NEIGHBORHOOD: 5,
+ STREET: 6,
+ EXACT: 8
+};
-function _hideHello() {
- Main.uiGroup.remove_actor(text);
- text = null;
-}
+const API_URL = 'http://api.open-notify.org/iss-now.json';
+// The minimal distance in km for icon to be made visible
+const SOUGHT_DISTANCE = 500;
+const CHECK_INTERVAL = 5 * 60; // how often (in sec) the check for ISS is done
+
+const ManagerIface = '<node> \
+ <interface name="org.freedesktop.GeoClue2.Manager"> \
+ <method name="GetClient"> \
+ <arg type="o" name="client" direction="out"/> \
+ </method> \
+ </interface> \
+</node>';
+const ManagerProxy = Gio.DBusProxy.makeProxyWrapper(ManagerIface);
+
+const ClientInterface = '<node> \
+<interface name="org.freedesktop.GeoClue2.Client"> \
+ <property name="Location" type="o" access="read"/> \
+ <property name="DesktopId" type="s" access="readwrite"/> \
+ <property name="RequestedAccuracyLevel" type="u" access="readwrite"/> \
+ <property name="DistanceThreshold" type="u" access="readwrite"/> \
+ <property name="Active" type="b" access="read"/> \
+ <method name="Start"/> \
+ <method name="Stop"/> \
+ <signal name="LocationUpdated"> \
+ <arg name="old" type="o"/> \
+ <arg name="new" type="o"/> \
+ </signal> \
+</interface> \
+</node>';
+const ClientProxy = Gio.DBusProxy.makeProxyWrapper(ClientInterface);
+
+const LocationInterface = '<node> \
+<interface name="org.freedesktop.GeoClue2.Location"> \
+ <property name="Latitude" type="d" access="read"/> \
+ <property name="Longitude" type="d" access="read"/> \
+ <property name="Accuracy" type="d" access="read"/> \
+ <property name="Description" type="s" access="read"/> \
+</interface> \
+</node>';
+const LocationProxy = Gio.DBusProxy.makeProxyWrapper(LocationInterface);
-function _showHello() {
- if (!text) {
- text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
- Main.uiGroup.add_actor(text);
+// global variables
+let text, button, label, client;
+
+const ISS_Above = new GObject.Class({
+ Name: 'ISS_Above',
+ Extends: GObject.Object,
+ Signals: {
+ 'processed_data': {
+ param_types: [
+ // GObject.TYPE_INT
+ ]
}
+ },
- text.opacity = 255;
+ _init: function(params) {
+ this.parent(params);
- let monitor = Main.layoutManager.primaryMonitor;
+ this.managerProxy = new ManagerProxy(Gio.DBus.system,
+ 'org.freedesktop.GeoClue2', '/org/freedesktop/GeoClue2/Manager');
- text.set_position(monitor.x + Math.floor(monitor.width / 2 - text.width / 2),
- monitor.y + Math.floor(monitor.height / 2 - text.height / 2));
+ [this.clientAddr] = this.managerProxy.GetClientSync();
- Tweener.addTween(text,
- { opacity: 0,
- time: 2,
- transition: 'easeOutQuad',
- onComplete: _hideHello });
-}
+ this.current_location = null;
+ this.iss_coords = null;
+ this.task_queue = 2; // number of async process to complete
+ this.timeout_source = null;
+
+ this.clientProxy = new ClientProxy(Gio.DBus.system,
+ 'org.freedesktop.GeoClue2', this.clientAddr);
+ this.clientProxy.DesktopId = 'gnome-shell-ISS_Above';
+ this.clientProxy.DistanceThreshold = 10000;
+ this.clientProxy.RequestedAccuracyLevel = AccuracyLevel.EXACT;
+ this.clientProxy.connectSignal('LocationUpdated',
+ Lang.bind(this, this.onLocationUpdated));
+ this.clientProxy.StartRemote();
+ this.connect('processed_data', Lang.bind(this, this.processResult));
+ },
+
+ run: function() {
+ this.getISScoords(function () {
+ print('run: processing new coords');
+ this.task_queue = 1;
+ this.processResult();
+ });
+ },
+
+ getISScoords: function (cb_process) {
+ let self = this;
+ let iss_api = Gio.file_new_for_uri(API_URL);
+ iss_api.load_contents_async(null, function(iss_api, result) {
+ self.iss_coords = JSON.parse(iss_api.load_contents_finish(result)[1]);
+ print('self.iss_coords = ' + self.iss_coords.toSource());
+ if (cb_process !== undefined) {
+ cb_process();
+ }
+ else {
+ self.emit('processed_data');
+ }
+ });
+ },
+
+ onLocationUpdated: function (proxy, sender, [oldPath, newPath]) {
+ let geoclueLocation = new LocationProxy(Gio.DBus.system,
+ "org.freedesktop.GeoClue2",
+ newPath);
+
+ // Yes, I take both null and undefined
+ if (geoclueLocation.Latitude != null) {
+ this.current_location = {
+ Latitude: geoclueLocation.Latitude,
+ Longitude: geoclueLocation.Longitude,
+ Accuracy: geoclueLocation.Accuracy,
+ Description: geoclueLocation.Description
+ };
+ }
+
+ this.emit('processed_data');
+ },
+
+ /**
+ * Calculate distance in km of two geographical points
+ *
+ * @param lat1 Number latitude of the first point
+ * @param long1 Number longitude of the first point
+ * @param lat2 Number latitude of the second point
+ * @param long2 Number longitude of the second point
+ * @return Number distance in km
+ *
+ * Described on https://en.wikipedia.org/wiki/Haversine_formula
+ */
+ get_distance: function(lat1, long1, lat2, long2) {
+ // Mean radius of the Earth in km
+ const EARTH_R = 6371;
+ const PI_180 = Math.PI / 180;
+
+ function haversin(fi) {
+ return (1 - Math.cos(fi)) / 2;
+ }
+
+ lat1 = lat1 * PI_180;
+ long1 = long1 * PI_180;
+ lat2 = lat2 * PI_180;
+ long2 = long2 * PI_180;
+
+ let dist = 2 * EARTH_R *
+ Math.asin(Math.sqrt(haversin(lat2 - lat1) +
+ Math.cos(lat1) * Math.cos(lat2) * haversin(long2 - long1)));
+
+ let test_haversin = haversin(dist / EARTH_R);
+ if (test_haversin < 1) {
+ return dist.toFixed(3);
+ }
+ else {
+ throw new Error('haversine(d/r) cannot be over 1, but it is ' +
+ test_haversin);
+ }
+ },
+
+ processResult: function() {
+ print('processResult, start: task_queue = ' + this.task_queue);
+ this.task_queue--;
+
+ if (this.task_queue === 0) {
+ print('processResult: our location: ' +
+ this.current_location.toSource());
+ print('processResult: iss coordinates: ' +
+ this.iss_coords.toSource());
+
+ let dist = this.get_distance(this.current_location.Latitude,
+ this.current_location.Longitude,
+ this.iss_coords.iss_position.latitude,
+ this.iss_coords.iss_position.longitude);
+ print('ISS is ' + dist + ' km away.');
+
+ // https://developer.gnome.org/clutter/stable/ClutterActor.html
+ if (dist < SOUGHT_DISTANCE) {
+ // Make the label text completely opaque
+ label.set_opacity(255);
+ print('Make label opaque');
+ }
+ else {
+ // Make the label text completely transparent
+ label.set_opacity(0);
+ print('Make label transparent');
+ }
+ }
+ }
+});
+
+// END of ISS_Above object definition
function init() {
- button = new St.Bin({ style_class: 'panel-button',
- reactive: true,
- can_focus: true,
- x_fill: true,
- y_fill: false,
- track_hover: true });
- let icon = new St.Icon({ icon_name: 'system-run-symbolic',
- style_class: 'system-status-icon' });
-
- button.set_child(icon);
- button.connect('button-press-event', _showHello);
}
function enable() {
- Main.panel._rightBox.insert_child_at_index(button, 0);
+ print('ENABLING ISS Above');
+ button = new St.Bin({ style_class: 'panel-button',
+ reactive: true,
+ can_focus: true,
+ x_fill: true,
+ y_fill: false,
+ track_hover: true });
+ // http://blog.fpmurphy.com/2011/04/replace-gnome-shell-activities-text-string-with-icon.html
+ label = new St.Label({ text: 'ISS' });
+ print('button is ' + button);
+
+ button.set_child(label);
+ label.set_opacity(0);
+
+ Main.panel._rightBox.insert_child_at_index(button, 0);
+
+ client = new ISS_Above();
+ client.getISScoords();
+
+ client.timeout_source = Mainloop.timeout_add_seconds(
+ CHECK_INTERVAL, client.run);
+
+ Mainloop.run();
}
function disable() {
- Main.panel._rightBox.remove_child(button);
+ print('DISABLING ISS Above');
+ Main.panel._rightBox.remove_child(button);
+ Mainloop.source_remove(client.timeout_source);
+
+ Mainloop.quit();
}
diff --git a/geoclue.js b/geoclue.js
deleted file mode 100755
index bcd0775..0000000
--- a/geoclue.js
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/gjs
-// Requires .desktop file installed in $XDG_DATA_DIRS/applications
-
-const GLib = imports.gi.GLib;
-const Gio = imports.gi.Gio;
-const Json = imports.gi.Json;
-const Lang = imports.lang;
-const Mainloop = imports.mainloop;
-
-const AccuracyLevel = {
- COUNTRY: 1,
- CITY: 4,
- NEIGHBORHOOD: 5,
- STREET: 6,
- EXACT: 8
-};
-
-const ManagerIface = '<node> \
- <interface name="org.freedesktop.GeoClue2.Manager"> \
- <method name="GetClient"> \
- <arg type="o" name="client" direction="out"/> \
- </method> \
- </interface> \
-</node>';
-const ManagerProxy = Gio.DBusProxy.makeProxyWrapper(ManagerIface);
-
-const ClientInterface = '<node> \
-<interface name="org.freedesktop.GeoClue2.Client"> \
- <property name="Location" type="o" access="read"/> \
- <property name="DesktopId" type="s" access="readwrite"/> \
- <property name="RequestedAccuracyLevel" type="u" access="readwrite"/> \
- <property name="DistanceThreshold" type="u" access="readwrite"/> \
- <property name="Active" type="b" access="read"/> \
- <method name="Start"/> \
- <method name="Stop"/> \
- <signal name="LocationUpdated"> \
- <arg name="old" type="o"/> \
- <arg name="new" type="o"/> \
- </signal> \
-</interface> \
-</node>';
-const ClientProxy = Gio.DBusProxy.makeProxyWrapper(ClientInterface);
-
-const LocationInterface = '<node> \
-<interface name="org.freedesktop.GeoClue2.Location"> \
- <property name="Latitude" type="d" access="read"/> \
- <property name="Longitude" type="d" access="read"/> \
- <property name="Accuracy" type="d" access="read"/> \
- <property name="Description" type="s" access="read"/> \
-</interface> \
-</node>';
-const LocationProxy = Gio.DBusProxy.makeProxyWrapper(LocationInterface);
-
-
-function onLocationUpdated(proxy, sender, [oldPath, newPath]) {
- let geoclueLocation = new LocationProxy(Gio.DBus.system,
- "org.freedesktop.GeoClue2",
- newPath);
- print('location:');
- print('\tlatitude = ' + geoclueLocation.Latitude);
- print('\tlongitude = ' + geoclueLocation.Longitude);
- print('\taccuracy = ' + geoclueLocation.Accuracy);
- print('\tdescription = ' + geoclueLocation.Description);
- //this._updateLocation(location);
- Mainloop.quit();
-}
-
-let _managerProxy = new ManagerProxy(Gio.DBus.system,
- 'org.freedesktop.GeoClue2', '/org/freedesktop/GeoClue2/Manager');
-
-let [clientAddr] = _managerProxy.GetClientSync();
-
-let clientProxy = new ClientProxy(Gio.DBus.system,
- 'org.freedesktop.GeoClue2', clientAddr);
-clientProxy.DesktopId = 'gnome-shell-ISS_Above';
-clientProxy.DistanceThreshold = 10000;
-clientProxy.RequestedAccuracyLevel = AccuracyLevel.EXACT;
-let updatedId = clientProxy.connectSignal('LocationUpdated',
- onLocationUpdated);
-clientProxy.StartRemote();
-
-Mainloop.run();
diff --git a/metadata.json b/metadata.json
index 36960bd..2eb1f76 100644
--- a/metadata.json
+++ b/metadata.json
@@ -4,5 +4,6 @@
],
"uuid": "ISS_Above@mcepl.cepl.eu",
"name": "ISS Above",
- "description": "Shows an icon when ISS is above you (+- 100km)"
+ "description": "Shows an icon when ISS is above you (+- 100km)",
+ "url": "https://gitlab.com/mcepl/gnome-shell-extension-ISS_Above/"
}
diff --git a/place.js b/place.js
deleted file mode 100644
index 91dd178..0000000
--- a/place.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
-/* vim: set et ts=4 sw=4: */
-/*
- * Copyright (c) 2014 Jonas Danielsson
- *
- * GNOME Maps is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * GNOME Maps is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with GNOME Maps; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author: Jonas Danielsson <jonas@threetimestwo.org>
- */
-
-const Geocode = imports.gi.GeocodeGlib;
-const GLib = imports.gi.GLib;
-const Lang = imports.lang;
-const Translations = imports.translations;
-
-const Place = new Lang.Class({
- Name: 'Place',
- Extends: Geocode.Place,
-
- _init: function(params) {
- this._population = params.population;
- delete params.population;
-
- this._wiki = params.wiki;
- delete params.wiki;
-
- this._openingHours = params.openingHours;
- delete params.openingHours;
-
- this._wheelchair = params.wheelchair;
- delete params.wheelchair;
-
- if (params.place) {
- params = { osm_id: params.place.osm_id,
- osm_type: params.place.osm_type,
- name: params.place.name,
- location: params.place.location,
- bounding_box: params.place.bounding_box,
- place_type: params.place.place_type,
- street_address: params.place.street_address,
- street: params.place.street,
- building: params.place.building,
- postal_code: params.place.postal_code,
- area: params.place.area,
- town: params.place.town,
- state: params.place.state,
- county: params.place.county,
- country: params.place.country,
- country_code: params.place.contry_code,
- continent: params.place.continent };
- }
-
- for (let prop in params)
- if (!params[prop])
- delete params[prop];
-
- this.parent(params);
- },
-
- get uniqueID() {
- return this.osm_type + '-' + this.osm_id;
- },
-
- set population(v) {
- this._population = v;
- },
-
- get population() {
- return this._population;
- },
-
- set wiki(v) {
- this._wiki = v;
- },
-
- get wiki() {
- return this._wiki;
- },
-
- set openingHours(v) {
- this._openingHours = v;
- },
-
- get openingHours() {
- return this._openingHours;
- },
-
- get openingHoursTranslated() {
- return Translations.translateOpeningHours(this._openingHours);
- },
-
- set wheelchair(v) {
- this._wheelchair = v;
- },
-
- get wheelchair() {
- return this._wheelchair;
- },
-
- get wheelchairTranslated() {
- return this._translateWheelchair(this._wheelchair);
- },
-
- _translateWheelchair: function(string) {
- switch(string) {
- /* Translators:
- * This means wheelchairs have full unrestricted access.
- */
- case 'yes': return _("yes");
-
- /* Translators:
- * This means wheelchairs have partial access (e.g some areas
- * can be accessed and others not, areas requiring assistance
- * by someone pushing up a steep gradient).
- */
- case 'limited': return _("limited");
-
- /* Translators:
- * This means wheelchairs have no unrestricted access
- * (e.g. stair only access).
- */
- case 'no': return _("no");
-
- /* Translators:
- * This means that the way or area is designated or purpose built
- * for wheelchairs (e.g. elevators designed for wheelchair access
- * only). This is rarely used.
- */
- case 'designated': return _("designated");
-
- default: return null;
- }
- },
-
-
- toJSON: function() {
- let bounding_box = null;
-
- if (this.bounding_box) {
- bounding_box = { top: this.bounding_box.top,
- bottom: this.bounding_box.bottom,
- left: this.bounding_box.left,
- right: this.bounding_box.right };
- }
-
- let location = { latitude: this.location.latitude,
- longitude: this.location.longitude,
- altitude: this.location.altitude,
- accuracy: this.location.accuracy };
-
- return { id: this.osm_id,
- osm_type: this.osm_type,
- name: this.name,
- bounding_box: bounding_box,
- this_type: this.this_type,
- location: location,
- street_address: this.street_address,
- street: this.street,
- building: this.building,
- postal_code: this.postal_code,
- area: this.area,
- town: this.town,
- state: this.state,
- county: this.county,
- country: this.country,
- country_code: this.contry_code,
- continent: this.continent,
- population: this.population,
- wiki: this.wiki,
- wheelchair: this.wheelchair,
- openingHours: this.openingHours };
- },
-
- match: function(searchString) {
- let name = this.name;
-
- searchString = GLib.utf8_normalize(searchString, -1, GLib.NormalizeMode.ALL);
- if (searchString === null)
- return false;
-
- if (searchString.length === 0)
- return true;
-
- name = GLib.utf8_normalize(name, -1, GLib.NormalizeMode.ALL);
- if (name === null)
- return false;
-
- return name.toLowerCase().search(searchString.toLowerCase()) !== -1;
- }
-});
-
-Place.fromJSON = function(obj) {
- let props = { };
-
- for (let key in obj) {
- let prop = obj[key];
-
- switch(key) {
- case 'id':
- props.osm_id = prop;
- break;
-
- case 'location':
- props.location = new Geocode.Location(prop);
- break;
-
- case 'bounding_box':
- if (prop)
- props.bounding_box = new Geocode.BoundingBox(prop);
- break;
-
- default:
- if (prop !== null && prop !== undefined)
- props[key] = prop;
- break;
- }
- }
- return new Place(props);
-};
diff --git a/stylesheet.css b/stylesheet.css
deleted file mode 100644
index 432a360..0000000
--- a/stylesheet.css
+++ /dev/null
@@ -1,8 +0,0 @@
-.helloworld-label {
- font-size: 36px;
- font-weight: bold;
- color: #ffffff;
- background-color: rgba(10,10,10,0.7);
- border-radius: 5px;
- padding: .5em;
-}