mirror of
https://github.com/moparisthebest/FireTray
synced 2024-12-21 21:48:47 -05:00
proof of concept version
This commit is contained in:
parent
1366a19410
commit
c842690051
@ -1,6 +1,6 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
Components.utils.import("resource://sce/commons.js");
|
||||
Components.utils.import("resource://mozt/commons.js");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<!DOCTYPE prefwindow SYSTEM "chrome://sce/locale/options.dtd">
|
||||
<prefwindow id="sce-preferences"
|
||||
<!DOCTYPE prefwindow SYSTEM "chrome://mozt/locale/options.dtd">
|
||||
<prefwindow id="mozt-preferences"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&prefwindow.title;"
|
||||
onload= "mozt.UIOptions.onLoad()">
|
||||
|
@ -1,63 +1,39 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/*
|
||||
* GLOBAL APPROACH:
|
||||
*
|
||||
* since we can't avoid the about:certerr page (1), and can't shortcut the
|
||||
* internal request to about:certerr gracefully (2), we:
|
||||
*
|
||||
* - add the cert exception
|
||||
* - wait for the full load of the about:certerr page (that's the tricky part)
|
||||
* - load the initially requested URL
|
||||
*
|
||||
* (1) certerror is hardly avoidable since it may be displayed whenever a
|
||||
* newsocket is created, see: nsNSSIOLayer.cpp: dialogs->ShowCertError,
|
||||
* nsNSSBadCertHandler, nsSSLIOLayerNewSocket,
|
||||
* ./netwerk/base/src/nsSocketTransport2.cpp
|
||||
*
|
||||
* (2) a raw reload of the requested https page works, but is not very clean
|
||||
* since it shortcuts the internal request to about:certerr, and produces a
|
||||
* harmless *no element found* error (displayed shortly and not too noticeable
|
||||
* though)
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://sce/commons.js");
|
||||
Components.utils.import("resource://mozt/commons.js");
|
||||
Components.utils.import("resource://mozt/LibGtkStatusIcon.js");
|
||||
|
||||
mozt.Main = {
|
||||
|
||||
onLoad: function() {
|
||||
// initialization code
|
||||
this.initialized = null;
|
||||
this.strings = document.getElementById("sce-strings");
|
||||
this.overrideService = null;
|
||||
this.recentCertsService = null;
|
||||
this.notification = {};
|
||||
this.stash = {};
|
||||
this.strings = document.getElementById("mozt-strings");
|
||||
|
||||
try {
|
||||
// Set up preference change observer
|
||||
mozt.Utils.prefService.QueryInterface(Ci.nsIPrefBranch2);
|
||||
// must stay out of _toggle()
|
||||
mozt.Utils.prefService.addObserver("", this, false);
|
||||
|
||||
// Get cert services
|
||||
this.overrideService =
|
||||
Cc["@mozilla.org/security/certoverride;1"]
|
||||
.getService(Components.interfaces.nsICertOverrideService);
|
||||
this.recentCertsService = Cc["@mozilla.org/security/recentbadcerts;1"]
|
||||
.getService(Ci.nsIRecentBadCertsService);
|
||||
}
|
||||
catch (ex) {
|
||||
Components.utils.reportError(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
var enabled = mozt.Utils.prefService.getBoolPref('enabled');
|
||||
mozt.Debug.dump('enabled: '+enabled);
|
||||
if (enabled)
|
||||
this._toggle(true);
|
||||
|
||||
mozt.Debug.dump('SkipCertError LOADED !');
|
||||
LibGtkStatusIcon.init();
|
||||
/*
|
||||
GtkStatusIcon *tray_icon = gtk_status_icon_new();
|
||||
GdkPixbuf *default_icon = gdk_pixbuf_new_from_xpm_data(firefox_xpm);
|
||||
gtk_status_icon_set_from_pixbuf(GTK_STATUS_ICON(tray_icon),
|
||||
GDK_PIXBUF(default_icon));
|
||||
*/
|
||||
this.tray_icon = LibGtkStatusIcon.gtk_status_icon_new();
|
||||
// var pixmap = "hi"; // TODO: read pixmap from file
|
||||
// LibGtkStatusIcon.gdk_pixbuf_new_from_xpm_data(pixmap);
|
||||
|
||||
mozt.Debug.dump('Moztray LOADED !');
|
||||
this.initialized = true;
|
||||
return true;
|
||||
},
|
||||
@ -65,30 +41,12 @@ mozt.Main = {
|
||||
onQuit: function() {
|
||||
// Remove observer
|
||||
mozt.Utils.prefService.removeObserver("", this);
|
||||
|
||||
this._toogle(false);
|
||||
LibGtkStatusIcon.shutdown();
|
||||
|
||||
mozt.Debug.dump('SkipCertError UNLOADED !');
|
||||
this.initialized = false;
|
||||
},
|
||||
|
||||
// since we are using a TabsProgressListener, it seems we do not need to keep
|
||||
// track of WebProgressListeners as indicated on
|
||||
// https://developer.mozilla.org/en/XUL_School/Intercepting_Page_Loads#WebProgressListeners
|
||||
_toggle: function (enable) {
|
||||
mozt.Debug.dump('toggle: '+enable);
|
||||
try {
|
||||
if (enable) {
|
||||
gBrowser.addTabsProgressListener(this.TabsProgressListener);
|
||||
} else {
|
||||
gBrowser.removeTabsProgressListener(this.TabsProgressListener);
|
||||
}
|
||||
} catch (ex) {
|
||||
Components.utils.reportError(ex);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
// Observer for pref changes
|
||||
if (topic != "nsPref:changed") return;
|
||||
@ -102,301 +60,6 @@ mozt.Main = {
|
||||
}
|
||||
},
|
||||
|
||||
_getCertException: function(uri, cert) {
|
||||
var outFlags = {};
|
||||
var outTempException = {};
|
||||
var knownCert = mozt.Main.overrideService.hasMatchingOverride(
|
||||
uri.asciiHost,
|
||||
uri.port,
|
||||
cert,
|
||||
outFlags,
|
||||
outTempException);
|
||||
return knownCert;
|
||||
},
|
||||
|
||||
_addCertException: function(SSLStatus, uri, cert) {
|
||||
var flags = 0;
|
||||
if(SSLStatus.isUntrusted)
|
||||
flags |= mozt.Main.overrideService.ERROR_UNTRUSTED;
|
||||
if(SSLStatus.isDomainMismatch)
|
||||
flags |= mozt.Main.overrideService.ERROR_MISMATCH;
|
||||
if(SSLStatus.isNotValidAtThisTime)
|
||||
flags |= mozt.Main.overrideService.ERROR_TIME;
|
||||
mozt.Main.overrideService.rememberValidityOverride(
|
||||
uri.asciiHost, uri.port,
|
||||
cert,
|
||||
flags,
|
||||
mozt.Utils.prefService.getBoolPref('add_temporary_exceptions'));
|
||||
mozt.Debug.dump("CertEx added");
|
||||
mozt.Main.TabsProgressListener._certExceptionJustAdded = true;
|
||||
mozt.Debug.dump("certEx changed: " + mozt.Main.TabsProgressListener._certExceptionJustAdded);
|
||||
|
||||
mozt.Main.TabsProgressListener._goto = uri.spec; // never reset
|
||||
},
|
||||
|
||||
_parseBadCertFlags: function(flags) {
|
||||
var tag = '';
|
||||
var ns = Ci.nsIX509Cert;
|
||||
|
||||
if (flags & ns.NOT_VERIFIED_UNKNOWN)
|
||||
tag += ', ' + mozt.Main.strings.getString('NOT_VERIFIED_UNKNOWN');
|
||||
if (flags & ns.CERT_REVOKED)
|
||||
tag += ', ' + mozt.Main.strings.getString('CERT_REVOKED');
|
||||
if (flags & ns.CERT_EXPIRED)
|
||||
tag += ', ' + mozt.Main.strings.getString('CERT_EXPIRED');
|
||||
if (flags & ns.CERT_NOT_TRUSTED)
|
||||
tag += ', ' + mozt.Main.strings.getString('CERT_NOT_TRUSTED');
|
||||
if (flags & ns.ISSUER_NOT_TRUSTED)
|
||||
tag += ', ' + mozt.Main.strings.getString('ISSUER_NOT_TRUSTED');
|
||||
if (flags & ns.ISSUER_UNKNOWN)
|
||||
tag += ', ' + mozt.Main.strings.getString('ISSUER_UNKNOWN');
|
||||
if (flags & ns.INVALID_CA)
|
||||
tag += ', ' + mozt.Main.strings.getString('INVALID_CA');
|
||||
if (flags & ns.USAGE_NOT_ALLOWED)
|
||||
tag += ', ' + mozt.Main.strings.getString('USAGE_NOT_ALLOWED');
|
||||
if (flags & SCE_CERT_SELF_SIGNED)
|
||||
tag += ', ' + mozt.Main.strings.getString('CERT_SELF_SIGNED');
|
||||
|
||||
if (tag != "") tag = tag.substr(2);
|
||||
|
||||
return tag;
|
||||
},
|
||||
|
||||
notify: function(abrowser) {
|
||||
|
||||
// find the correct tab to display notification on
|
||||
var mainWindow = window
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem).rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
|
||||
var notificationBox = mainWindow.gBrowser.getNotificationBox(abrowser);
|
||||
mozt.Main.stash.notificationBox = notificationBox; // stash for later use
|
||||
|
||||
// check notification not already here
|
||||
var notificationValue = mozt.Main.notification.type + '_' + mozt.Main.notification.host;
|
||||
if (notificationBox.getNotificationWithValue(notificationValue)) {
|
||||
mozt.Debug.dump("notificationBox already here");
|
||||
return;
|
||||
}
|
||||
|
||||
// build notification
|
||||
var temporaryException = mozt.Utils.prefService.getBoolPref('add_temporary_exceptions') ?
|
||||
mozt.Main.strings.getString('temporaryException') : mozt.Main.strings.getString('permanentException');
|
||||
var msgArgs = [];
|
||||
var priority = null; // notificationBox.PRIORITY_INFO_LOW not working ??
|
||||
switch (mozt.Main.notification.type) {
|
||||
case 'exceptionAdded':
|
||||
msgArgs = [temporaryException, mozt.Main.notification.host];
|
||||
priority = 'PRIORITY_INFO_LOW';
|
||||
break;
|
||||
case 'exceptionNotAdded':
|
||||
msgArgs = [mozt.Main.notification.dontBypassFlags];
|
||||
priority = 'PRIORITY_WARNING_LOW';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
var message = mozt.Main.strings.getFormattedString(
|
||||
mozt.Main.notification.type, msgArgs);
|
||||
|
||||
// appendNotification( label , value , image , priority , buttons )
|
||||
var notification = notificationBox.appendNotification(
|
||||
message, notificationValue, null, notificationBox[priority], null);
|
||||
|
||||
// close notificatioBox if needed (will close automatically if reload)
|
||||
var exceptionDialogButton = abrowser.webProgress.DOMWindow
|
||||
.document.getElementById('exceptionDialogButton');
|
||||
exceptionDialogButton.addEventListener(
|
||||
"click", mozt.Main.exceptionDialogButtonOnClick, false);
|
||||
|
||||
mozt.Main.notification = {}; // reset
|
||||
},
|
||||
|
||||
exceptionDialogButtonOnClick: function(event) {
|
||||
mozt.Main._closeNotificationMaybe();
|
||||
event.originalTarget.removeEventListener(
|
||||
"click", mozt.Main.exceptionDialogButtonOnClick, false);
|
||||
},
|
||||
|
||||
_closeNotificationMaybe: function() {
|
||||
if (!mozt.Main.stash.notificationBox)
|
||||
return;
|
||||
mozt.Main.stash.notificationBox.currentNotification.close();
|
||||
mozt.Main.stash.notificationBox = null;
|
||||
},
|
||||
|
||||
|
||||
// a TabProgressListner seems more appropriate than an Observer, which only
|
||||
// gets notified for document requests (not internal requests)
|
||||
TabsProgressListener: {
|
||||
// can't see the necessity of having QueryInterface(aIID) implemented...
|
||||
|
||||
_certExceptionJustAdded: null, // used for communication btw
|
||||
// onSecurityChange, onStateChange, ...
|
||||
_certerrorCount: 0, // certerr seems called more than once...
|
||||
|
||||
// This method will be called on security transitions (eg HTTP -> HTTPS,
|
||||
// HTTPS -> HTTP, FOO -> HTTPS) and *after document load* completion. It
|
||||
// might also be called if an error occurs during network loading.
|
||||
onSecurityChange: function (aBrowser, aWebProgress, aRequest, aState) {
|
||||
var uri = aBrowser.currentURI;
|
||||
mozt.Debug.dump("onSecurityChange: uri=" + uri.prePath);
|
||||
|
||||
if (!uri.schemeIs("https")) return;
|
||||
|
||||
this._certerrorCount = 0; // reset
|
||||
|
||||
// retrieve bad cert from nsIRecentBadCertsService
|
||||
// NOTE: experience shows that nsIRecentBadCertsService will not provide
|
||||
// SSLStatus when cert is known or trusted. That's why we don't try to
|
||||
// get it from aRequest
|
||||
var port = uri.port;
|
||||
if (port == -1) port = 443; // thx http://gitorious.org/perspectives-notary-server/
|
||||
var hostWithPort = uri.host + ":" + port;
|
||||
mozt.Main.notification.host = uri.host;
|
||||
var SSLStatus = mozt.Main.recentCertsService.getRecentBadCert(hostWithPort);
|
||||
|
||||
if (!SSLStatus) {
|
||||
mozt.Debug.dump("no SSLStatus for: " + hostWithPort);
|
||||
return;
|
||||
}
|
||||
|
||||
mozt.Debug.dump("SSLStatus");
|
||||
mozt.Debug.dumpObj(SSLStatus);
|
||||
var cert = SSLStatus.serverCert;
|
||||
mozt.Debug.dump("cert");
|
||||
mozt.Debug.dumpObj(cert);
|
||||
|
||||
// check if cert already known/added
|
||||
var knownCert = mozt.Main._getCertException(uri, cert);
|
||||
if (knownCert) {
|
||||
mozt.Debug.dump("known cert: " + knownCert);
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine cert problems
|
||||
var dontBypassFlags = 0;
|
||||
|
||||
// we're only interested in certs with characteristics
|
||||
// defined in options (self-signed, issuer unknown, ...)
|
||||
cert.QueryInterface(Ci.nsIX509Cert3);
|
||||
var isSelfSigned = cert.isSelfSigned;
|
||||
mozt.Debug.dump("isSelfSigned:" + isSelfSigned);
|
||||
if (isSelfSigned
|
||||
&& !mozt.Utils.prefService.getBoolPref("bypass_self_signed"))
|
||||
dontBypassFlags |= SCE_CERT_SELF_SIGNED;
|
||||
// NOTE: isSelfSigned *implies* ISSUER_UNKNOWN (should be handled
|
||||
// correctly in option dialog)
|
||||
|
||||
var verificationResult = cert.verifyForUsage(Ci.nsIX509Cert.CERT_USAGE_SSLServer);
|
||||
switch (verificationResult) {
|
||||
case Ci.nsIX509Cert.ISSUER_NOT_TRUSTED: // including self-signed
|
||||
mozt.Debug.dump("issuer not trusted");
|
||||
case Ci.nsIX509Cert.ISSUER_UNKNOWN:
|
||||
mozt.Debug.dump("issuer unknown");
|
||||
mozt.Debug.dump("bypass_issuer_unknown: " + mozt.Utils.prefService.getBoolPref("bypass_issuer_unknown"));
|
||||
if (!mozt.Utils.prefService.getBoolPref("bypass_issuer_unknown"))
|
||||
dontBypassFlags |= Ci.nsIX509Cert.ISSUER_UNKNOWN;
|
||||
default:
|
||||
mozt.Debug.dump("verificationResult: " + verificationResult);
|
||||
break;
|
||||
}
|
||||
var dontBypassTag = mozt.Main._parseBadCertFlags(dontBypassFlags);
|
||||
mozt.Debug.dump("dontBypassFlags=" + dontBypassFlags + ", " + dontBypassTag);
|
||||
|
||||
// trigger notification
|
||||
if (mozt.Utils.prefService.getBoolPref('notify')) {
|
||||
mozt.Main.notification.willNotify = true;
|
||||
mozt.Debug.dump("onSecurityChange: willNotify");
|
||||
}
|
||||
|
||||
// Add cert exception (if bypass allowed by options)
|
||||
if (dontBypassFlags == 0) {
|
||||
mozt.Main._addCertException(SSLStatus, uri, cert);
|
||||
mozt.Main.notification.type = 'exceptionAdded';
|
||||
} else {
|
||||
mozt.Main.notification.type = 'exceptionNotAdded';
|
||||
mozt.Main.notification.dontBypassFlags = dontBypassTag;
|
||||
}
|
||||
|
||||
}, // END onSecurityChange
|
||||
|
||||
_getTabIndex: function(abrowser) {
|
||||
var tabbrowser = abrowser.getTabBrowser();
|
||||
var tabContainer = tabbrowser.tabs;
|
||||
|
||||
var tabIndex = null;
|
||||
for (var i = 0; i < tabContainer.length; ++i) {
|
||||
if (abrowser == tabbrowser.getBrowserAtIndex(i)) {
|
||||
tabIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tabIndex;
|
||||
},
|
||||
|
||||
// "We can't look for this during onLocationChange since at that point the
|
||||
// document URI is not yet the about:-uri of the error page." (browser.js)
|
||||
// Experience shows that the order is as follows: badcert
|
||||
// (onSecurityChange) leading to about:blank, then request of
|
||||
// about:document-onload-blocker, leading to about:certerror (called at
|
||||
// least twice)
|
||||
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
|
||||
// aProgress.DOMWindow is the tab/window which triggered the change.
|
||||
var originDoc = aWebProgress.DOMWindow.document;
|
||||
var originURI = originDoc.documentURI;
|
||||
mozt.Debug.dump("onStateChange " + this._getTabIndex(aBrowser) + ": originURI=" + originURI);
|
||||
var safeRequestName = mozt.Utils.safeGetName(aRequest);
|
||||
mozt.Debug.dump("safeRequestName: " + safeRequestName);
|
||||
|
||||
// WE JUST CAN'T CANCEL THE REQUEST FOR about:certerr |
|
||||
// about:document-onload-blocker ...SO WE WAIT FOR IT !
|
||||
if (aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP
|
||||
|Ci.nsIWebProgressListener.STATE_IS_REQUEST)) {
|
||||
|
||||
if (/^about:certerr/.test(originURI)) {
|
||||
this._certerrorCount++;
|
||||
mozt.Debug.dump("certerrorCount=" + this._certerrorCount);
|
||||
|
||||
if (this._certerrorCount < 2) {
|
||||
if (aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP
|
||||
|Ci.nsIWebProgressListener.STATE_RESTORING)) {
|
||||
// experienced only one certerr call during sessoin restore
|
||||
mozt.Debug.dump("restoring");
|
||||
} else {
|
||||
mozt.Debug.dump("certerrorCount not sufficient");
|
||||
return; // wait for last (?) call
|
||||
}
|
||||
}
|
||||
|
||||
if (this._certExceptionJustAdded) {
|
||||
this._certExceptionJustAdded = false; // reset
|
||||
mozt.Debug.dump("certEx changed: " + this._certExceptionJustAdded);
|
||||
|
||||
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
|
||||
aBrowser.loadURI(this._goto, null, null);
|
||||
}
|
||||
|
||||
if (mozt.Main.notification.willNotify) {
|
||||
mozt.Debug.dump("onStateChange: willNotify");
|
||||
mozt.Main.notify.willNotify = false; // reset
|
||||
mozt.Main.notify(aBrowser);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, // END onStateChange
|
||||
|
||||
onLocationChange: function() { },
|
||||
onProgressChange: function() { },
|
||||
onStatusChange: function() { },
|
||||
|
||||
}, // END TabsProgressListener
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
BIN
src/chrome/skin/icon32.png
Normal file
BIN
src/chrome/skin/icon32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB |
@ -1,22 +1,22 @@
|
||||
/* This is just an example. You shouldn't do this. */
|
||||
#sce-hello
|
||||
#mozt-hello
|
||||
{
|
||||
color: red ! important;
|
||||
}
|
||||
#sce-toolbar-button
|
||||
#mozt-toolbar-button
|
||||
{
|
||||
list-style-image: url("chrome://sce/skin/toolbar-button.png");
|
||||
list-style-image: url("chrome://mozt/skin/toolbar-button.png");
|
||||
-moz-image-region: rect(0px 24px 24px 0px);
|
||||
}
|
||||
#sce-toolbar-button:hover
|
||||
#mozt-toolbar-button:hover
|
||||
{
|
||||
-moz-image-region: rect(24px 24px 48px 0px);
|
||||
}
|
||||
[iconsize="small"] #sce-toolbar-button
|
||||
[iconsize="small"] #mozt-toolbar-button
|
||||
{
|
||||
-moz-image-region: rect( 0px 40px 16px 24px);
|
||||
}
|
||||
[iconsize="small"] #sce-toolbar-button:hover
|
||||
[iconsize="small"] #mozt-toolbar-button:hover
|
||||
{
|
||||
-moz-image-region: rect(24px 40px 40px 24px);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// https://developer.mozilla.org/en/Localizing_extension_descriptions
|
||||
pref("extensions.skipcerterror@foudil.fr.description", "chrome://sce/locale/overlay.properties");
|
||||
pref("extensions.skipcerterror@foudil.fr.description", "chrome://mozt/locale/overlay.properties");
|
||||
|
||||
// Extension prefs
|
||||
pref("extensions.mozt.enabled", true);
|
||||
|
@ -1,19 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>skipcerterror@foudil.fr</em:id>
|
||||
<em:id>moztray@foudil.fr</em:id>
|
||||
<em:unpack>false</em:unpack>
|
||||
<em:type>2</em:type>
|
||||
<em:name>Mozilla Tray</em:name>
|
||||
<em:version>0.0.1</em:version>
|
||||
<em:creator>Foudil BRÉTEL</em:creator>
|
||||
<em:contributor></em:contributor>
|
||||
<em:contributor>Hua Luo, Francesco Solero (Firetray original authors)</em:contributor>
|
||||
<em:homepageURL>https://github.com/foudfou/moztray</em:homepageURL>
|
||||
<em:description></em:description>
|
||||
<em:optionsURL>chrome://mozt/content/options.xul</em:optionsURL>
|
||||
<em:iconURL>chrome://mozt/skin/icon48.png</em:iconURL>
|
||||
<em:icon64URL>chrome://mozt/skin/icon64.png</em:icon64URL>
|
||||
<!-- <em:optionsURL>chrome://mozt/content/options.xul</em:optionsURL> -->
|
||||
<em:iconURL>chrome://mozt/skin/icon32.png</em:iconURL>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- Firefox -->
|
||||
|
81
src/modules/LibGtkStatusIcon.js
Normal file
81
src/modules/LibGtkStatusIcon.js
Normal file
@ -0,0 +1,81 @@
|
||||
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
var EXPORTED_SYMBOLS = ["LibGtkStatusIcon"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const LIB_GTK = "libgtk-x11-2.0.so";
|
||||
|
||||
var LibGtkStatusIcon = {
|
||||
|
||||
_lib: null,
|
||||
|
||||
init: function() {
|
||||
// If ctypes doesn't exist, try to get it
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
// If we still don't have ctypes, this isn't going to work...
|
||||
if (typeof(ctypes) == "undefined") {
|
||||
throw ("Could not load JS-Ctypes");
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to start up dependencies - if they fail, they'll throw
|
||||
// exceptions. ex: GObjectLib.init();
|
||||
|
||||
this._lib = ctypes.open(LIB_GTK);
|
||||
if (!this._lib)
|
||||
throw ("Could not load " + LIB_GTK);
|
||||
|
||||
} catch (e) {
|
||||
this.shutdown();
|
||||
throw(e);
|
||||
}
|
||||
|
||||
// Ok, we got everything - let's declare.
|
||||
this._declare();
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
// Close our connection to the library.
|
||||
if (this._lib)
|
||||
this._lib.close();
|
||||
},
|
||||
|
||||
_declare: function() {
|
||||
// Types
|
||||
this.GtkStatusIcon = ctypes.StructType("GtkStatusIcon");
|
||||
this.GtkStatusIconRef = ctypes.PointerType(this.GtkStatusIcon);
|
||||
this.GdkPixbuf = ctypes.StructType("GdkPixbuf");
|
||||
this.GdkPixbufRef = ctypes.PointerType(this.GdkPixbuf);
|
||||
this.Pixbuf = ctypes.PointerType(ctypes.char.ptr);
|
||||
|
||||
// Consts
|
||||
this.INDICATOR_MESSAGES_SERVER_TYPE = "message";
|
||||
|
||||
// Functions
|
||||
|
||||
this.gtk_status_icon_new = this._lib.declare(
|
||||
"gtk_status_icon_new",
|
||||
ctypes.default_abi,
|
||||
this.GtkStatusIconRef
|
||||
);
|
||||
|
||||
this.gdk_pixbuf_new_from_xpm_data = this._lib.declare(
|
||||
"gdk_pixbuf_new_from_xpm_data",
|
||||
ctypes.default_abi,
|
||||
this.GdkPixbufRef,
|
||||
this.Pixbuf
|
||||
);
|
||||
|
||||
this.gtk_status_icon_set_from_pixbuf = this._lib.declare(
|
||||
"gtk_status_icon_set_from_pixbuf",
|
||||
ctypes.default_abi,
|
||||
this.GtkStatusIconRef,
|
||||
this.GdkPixbufRef
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
};
|
4
testing/Makefile
Normal file
4
testing/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
includes := $(shell pkg-config --libs --cflags gtk+-2.0)
|
||||
|
||||
all:
|
||||
gcc $(includes) -o gtk_icon_example gkt_icon_example.c
|
3096
testing/firefox.xpm
Normal file
3096
testing/firefox.xpm
Normal file
File diff suppressed because it is too large
Load Diff
45
testing/gkt_icon_example.c
Normal file
45
testing/gkt_icon_example.c
Normal file
@ -0,0 +1,45 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include "firefox.xpm"
|
||||
|
||||
void tray_icon_on_click(GtkStatusIcon *status_icon,
|
||||
gpointer user_data)
|
||||
{
|
||||
printf("Clicked on tray icon\n");
|
||||
}
|
||||
|
||||
void tray_icon_on_menu(GtkStatusIcon *status_icon, guint button,
|
||||
guint activate_time, gpointer user_data)
|
||||
{
|
||||
printf("Popup menu\n");
|
||||
}
|
||||
|
||||
static GtkStatusIcon *create_tray_icon() {
|
||||
GtkStatusIcon *tray_icon;
|
||||
|
||||
tray_icon = gtk_status_icon_new();
|
||||
g_signal_connect(G_OBJECT(tray_icon), "activate",
|
||||
G_CALLBACK(tray_icon_on_click), NULL);
|
||||
g_signal_connect(G_OBJECT(tray_icon),
|
||||
"popup-menu",
|
||||
G_CALLBACK(tray_icon_on_menu), NULL);
|
||||
|
||||
GdkPixbuf *default_icon = gdk_pixbuf_new_from_xpm_data(firefox_xpm);
|
||||
|
||||
gtk_status_icon_set_from_pixbuf(GTK_STATUS_ICON(tray_icon),
|
||||
GDK_PIXBUF(default_icon));
|
||||
gtk_status_icon_set_tooltip(tray_icon,
|
||||
"Example Tray Icon");
|
||||
gtk_status_icon_set_visible(tray_icon, TRUE);
|
||||
|
||||
return tray_icon;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
GtkStatusIcon *tray_icon;
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
tray_icon = create_tray_icon();
|
||||
gtk_main();
|
||||
|
||||
return 0;
|
||||
}
|
BIN
testing/gtk_icon_example
Executable file
BIN
testing/gtk_icon_example
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user