new snarl notification plugin
This commit is contained in:
1
snarl_notifications/__init__.py
Normal file
1
snarl_notifications/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from plugin import SnarlNotificationsPlugin
|
||||||
11
snarl_notifications/manifest.ini
Normal file
11
snarl_notifications/manifest.ini
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[info]
|
||||||
|
name: Snarl Notifications
|
||||||
|
short_name: snarl_notifications
|
||||||
|
version: 0.1
|
||||||
|
description: Shows events notification using Snarl (http://www.fullphat.net/) under Windows. Snarl needs to be installed in system.
|
||||||
|
PySnarl bindings are used (http://sourceforge.net/projects/pysnarl/).
|
||||||
|
authors = Yann Leboulanger <asterix@lagaule.org>
|
||||||
|
homepage = http://trac-plugins.gajim.org/wiki/SnarlNotificationsPlugin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
89
snarl_notifications/plugin.py
Normal file
89
snarl_notifications/plugin.py
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##
|
||||||
|
## This file is part of Gajim.
|
||||||
|
##
|
||||||
|
## Gajim 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; version 3 only.
|
||||||
|
##
|
||||||
|
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
##
|
||||||
|
'''
|
||||||
|
Events notifications using Snarl
|
||||||
|
|
||||||
|
Fancy events notifications under Windows using Snarl infrastructure.
|
||||||
|
|
||||||
|
:note: plugin is at proof-of-concept state.
|
||||||
|
|
||||||
|
:author: Yann Leboulanger <asterix@lagaule.org>
|
||||||
|
:since: 08 April 2012
|
||||||
|
:copyright: Copyright (2012) Yann Leboulanger <asterix@lagaule.org>
|
||||||
|
:license: GPL
|
||||||
|
'''
|
||||||
|
|
||||||
|
import pySnarl
|
||||||
|
|
||||||
|
from common import gajim
|
||||||
|
from plugins import GajimPlugin
|
||||||
|
from plugins.helpers import log_calls, log
|
||||||
|
from common import ged
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
class SnarlActionHandler(pySnarl.EventHandler):
|
||||||
|
def OnNotificationInvoked(self, uid):
|
||||||
|
account, jid, msg_type = uid.split()
|
||||||
|
gajim.interface.handle_event(account, jid, msg_type)
|
||||||
|
|
||||||
|
class SnarlNotificationsPlugin(GajimPlugin):
|
||||||
|
|
||||||
|
@log_calls('SnarlNotificationsPlugin')
|
||||||
|
def init(self):
|
||||||
|
self.description = _('Shows events notification using Snarl '
|
||||||
|
'(http://www.fullphat.net/) under Windows. '
|
||||||
|
'Snarl needs to be installed in system.\n'
|
||||||
|
'PySnarl bindings are used (http://code.google.com/p/pysnarl/).')
|
||||||
|
self.config_dialog = None
|
||||||
|
self.h = SnarlActionHandler
|
||||||
|
self.snarl_win = pySnarl.SnarlApp(
|
||||||
|
"pySnarl/Gajim", # app signature
|
||||||
|
"Gajim", # app title
|
||||||
|
os.path.abspath("..\data\pixmaps\gajim.ico"), # icon
|
||||||
|
"", # config Tool
|
||||||
|
"Gajim will use Snarl to display notifications", # hint
|
||||||
|
False, # IsDaemon
|
||||||
|
self.h, # event handler
|
||||||
|
[] # classes
|
||||||
|
)
|
||||||
|
|
||||||
|
self.events_handlers = {'notification' : (ged.PRECORE, self.notif)}
|
||||||
|
|
||||||
|
@log_calls('SnarlNotificationsPlugin')
|
||||||
|
def notif(self, obj):
|
||||||
|
if obj.do_popup:
|
||||||
|
uid = obj.conn.name + " " + obj.jid + " " + obj.popup_msg_type
|
||||||
|
self.snarl_win.notify(
|
||||||
|
[], # actions
|
||||||
|
"", # callbackScript
|
||||||
|
"", # callbackScriptType
|
||||||
|
"", # class
|
||||||
|
"", # defaultCallback
|
||||||
|
5, # duration
|
||||||
|
os.path.abspath(obj.popup_image),#r"C:\Documents and Settings\Administrateur\Mes documents\gajim\data\pixmaps\gajim.ico", # icon
|
||||||
|
"", # mergeUID
|
||||||
|
0, # priority
|
||||||
|
"", # replaceUID
|
||||||
|
obj.popup_text,
|
||||||
|
obj.popup_title,
|
||||||
|
uid, # UID
|
||||||
|
"", # sound
|
||||||
|
-1, # percent
|
||||||
|
0, # log
|
||||||
|
64, # sensitivity
|
||||||
|
)
|
||||||
|
obj.do_popup = False
|
||||||
365
snarl_notifications/pySnarl.py
Normal file
365
snarl_notifications/pySnarl.py
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# ActiveX/COM Snarl python library
|
||||||
|
# For proper functioning requires Snarl 2.5.1 or later !
|
||||||
|
# Version 0.0.2
|
||||||
|
|
||||||
|
# Changelog (in reverse chronological order):
|
||||||
|
# -------------------------------------------
|
||||||
|
# 0.0.2 by Pako 2012-01-30 14:12 UTC+1
|
||||||
|
# - base64 icon format is now supported
|
||||||
|
# 0.0.1 by Pako 2012-01-06 15:30 UTC+1
|
||||||
|
# - initial version
|
||||||
|
#-------------------------------------------------------
|
||||||
|
|
||||||
|
from win32com.client import constants, gencache, Dispatch, DispatchWithEvents
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
def IsRunning():
|
||||||
|
from win32gui import FindWindow
|
||||||
|
return FindWindow("w>Snarl", "Snarl")
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
class EventHandler:
|
||||||
|
|
||||||
|
def OnActivated(self):
|
||||||
|
self.fn("DaemonActivated")
|
||||||
|
|
||||||
|
def OnNotificationActionSelected(self, uid, command):
|
||||||
|
self.fn("ActionSelected.%s" % command, payload = uid)
|
||||||
|
|
||||||
|
def OnNotificationClosed(self, uid):
|
||||||
|
self.fn("Closed", payload = uid)
|
||||||
|
|
||||||
|
def OnNotificationExpired(self, uid):
|
||||||
|
self.fn("Expired", payload = uid)
|
||||||
|
|
||||||
|
def OnNotificationInvoked(self, uid):
|
||||||
|
self.fn("Invoked", payload = uid)
|
||||||
|
|
||||||
|
def OnQuit(self):
|
||||||
|
self.fn("AppQuit")
|
||||||
|
|
||||||
|
def OnShowAbout(self):
|
||||||
|
self.fn("ShowAbout")
|
||||||
|
|
||||||
|
def OnShowConfig(self):
|
||||||
|
self.fn("ShowConfig")
|
||||||
|
|
||||||
|
def OnSnarlLaunched(self):
|
||||||
|
self.fn("Launched")
|
||||||
|
|
||||||
|
def OnSnarlQuit(self):
|
||||||
|
self.fn("Quit")
|
||||||
|
|
||||||
|
def OnSnarlStarted(self):
|
||||||
|
self.fn("Started")
|
||||||
|
|
||||||
|
def OnSnarlStopped(self):
|
||||||
|
self.fn("Stopped")
|
||||||
|
|
||||||
|
def OnUserAway(self):
|
||||||
|
self.fn("UserAway")
|
||||||
|
|
||||||
|
def OnUserReturned(self):
|
||||||
|
self.fn("UserReturned")
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
class SnarlApp(object):
|
||||||
|
"""Creates an SnarlApp object"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
signature,
|
||||||
|
title,
|
||||||
|
icon = "",
|
||||||
|
configTool = "",
|
||||||
|
hint = "",
|
||||||
|
isDaemon = False,
|
||||||
|
eventHandler = None,
|
||||||
|
classes = []
|
||||||
|
):
|
||||||
|
self.app = gencache.EnsureDispatch("libsnarl25.SnarlApp")
|
||||||
|
for d in constants.__dicts__: # we must find the right dictionary ...
|
||||||
|
if 'ERROR_NOTIFICATION_NOT_FOUND' in d: # this is it !
|
||||||
|
break
|
||||||
|
codes = d.items()
|
||||||
|
codes.sort(reverse = True)
|
||||||
|
self.statCodes = dict([[v,k] for k,v in codes[6:]])
|
||||||
|
self.statCodes[codes[2][1]] = codes[2][0] # added SUCCESS
|
||||||
|
self.classes = NotifClasses(classes)
|
||||||
|
if eventHandler:
|
||||||
|
self.SetEventHandler(eventHandler)
|
||||||
|
self.SetTo(
|
||||||
|
configTool,
|
||||||
|
hint,
|
||||||
|
icon,
|
||||||
|
isDaemon,
|
||||||
|
signature,
|
||||||
|
title
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def SetTo(
|
||||||
|
self,
|
||||||
|
configTool,
|
||||||
|
hint,
|
||||||
|
icon,
|
||||||
|
isDaemon,
|
||||||
|
signature,
|
||||||
|
title
|
||||||
|
):
|
||||||
|
self.app.Classes = self.classes.Classes()
|
||||||
|
self.app.ConfigTool = configTool
|
||||||
|
self.app.Hint = hint
|
||||||
|
self.app.Icon = icon
|
||||||
|
self.app.IsDaemon = isDaemon
|
||||||
|
self.app.Signature = signature
|
||||||
|
self.app.Title = title
|
||||||
|
|
||||||
|
|
||||||
|
def GetStatusCode(self, code):
|
||||||
|
return self.statCodes[code]
|
||||||
|
|
||||||
|
|
||||||
|
def SetEventHandler(self, handler):
|
||||||
|
self.events = DispatchWithEvents(self.app, handler)
|
||||||
|
|
||||||
|
|
||||||
|
def register(self):
|
||||||
|
return self.GetStatusCode(self.app.Register())
|
||||||
|
|
||||||
|
|
||||||
|
def unregister(self):
|
||||||
|
return self.GetStatusCode(self.app.Unregister())
|
||||||
|
|
||||||
|
|
||||||
|
def tidyUp(self):
|
||||||
|
self.app.TidyUp()
|
||||||
|
|
||||||
|
|
||||||
|
def addClass(
|
||||||
|
self,
|
||||||
|
classId,
|
||||||
|
name,
|
||||||
|
enabled = True,
|
||||||
|
title = "",
|
||||||
|
text = "",
|
||||||
|
icon = "",
|
||||||
|
callback = "",
|
||||||
|
duration = -1,
|
||||||
|
sound = "",
|
||||||
|
):
|
||||||
|
cntOld = self.classes.count()
|
||||||
|
cntNew = self.classes.add(classId, name, enabled, title, text, icon, callback, duration, sound)
|
||||||
|
return int(not cntNew == cntOld + 1)
|
||||||
|
|
||||||
|
|
||||||
|
def remClass(self, id):
|
||||||
|
cntOld = self.classes.count()
|
||||||
|
cntNew = self.classes.remove(id)
|
||||||
|
return int(not cntNew == cntOld - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def clearClasses(self):
|
||||||
|
return self.classes.makeEmpty()
|
||||||
|
|
||||||
|
|
||||||
|
def classesCount(self):
|
||||||
|
return self.classes.count()
|
||||||
|
|
||||||
|
|
||||||
|
def notify(
|
||||||
|
self,
|
||||||
|
actions,
|
||||||
|
callbackScript,
|
||||||
|
callbackScriptType,
|
||||||
|
cls,
|
||||||
|
defaultCallback,
|
||||||
|
duration,
|
||||||
|
icon,
|
||||||
|
mergeUID,
|
||||||
|
priority,
|
||||||
|
replaceUID,
|
||||||
|
text,
|
||||||
|
title,
|
||||||
|
uid,
|
||||||
|
sound = None,
|
||||||
|
percent = None,
|
||||||
|
log = None,
|
||||||
|
sensitivity = None
|
||||||
|
):
|
||||||
|
note = Notification(
|
||||||
|
actions,
|
||||||
|
callbackScript,
|
||||||
|
callbackScriptType,
|
||||||
|
cls,
|
||||||
|
defaultCallback,
|
||||||
|
duration,
|
||||||
|
"",
|
||||||
|
mergeUID,
|
||||||
|
priority,
|
||||||
|
replaceUID,
|
||||||
|
text,
|
||||||
|
title,
|
||||||
|
uid,
|
||||||
|
)
|
||||||
|
if icon:
|
||||||
|
if icon[1] == ":":
|
||||||
|
note.Add("icon", icon, True)
|
||||||
|
else:
|
||||||
|
note.Add("icon-base64", icon.replace("=","%"), True)
|
||||||
|
if sound:
|
||||||
|
note.Add("sound", sound, True)
|
||||||
|
if percent is not None and percent > -1:
|
||||||
|
note.Add("value-percent", str(percent), True)
|
||||||
|
if log is not None:
|
||||||
|
note.Add("log", str(log), True)
|
||||||
|
if sensitivity is not None:
|
||||||
|
note.Add("sensitivity", str(sensitivity), True)
|
||||||
|
return self.GetStatusCode(self.app.Show(note.Note())[0])
|
||||||
|
|
||||||
|
|
||||||
|
def hideNotification(self, uid):
|
||||||
|
return self.GetStatusCode(self.app.Hide(uid))
|
||||||
|
|
||||||
|
|
||||||
|
def isVisible(self, uid):
|
||||||
|
return self.GetStatusCode(self.app.IsVisible(uid))
|
||||||
|
|
||||||
|
|
||||||
|
def getEtcPath(self):
|
||||||
|
return self.app.GetEtcPath()
|
||||||
|
|
||||||
|
|
||||||
|
def makePath(self, pth):
|
||||||
|
return self.app.GetEtcPath(pth)
|
||||||
|
|
||||||
|
|
||||||
|
def isInstalled(self):
|
||||||
|
return self.app.IsSnarlInstalled()
|
||||||
|
|
||||||
|
|
||||||
|
def isRunning(self):
|
||||||
|
return self.app.IsSnarlRunning()
|
||||||
|
|
||||||
|
|
||||||
|
def version(self):
|
||||||
|
ver = self.app.SnarlVersion()
|
||||||
|
return ver if ver > 0 else self.GetStatusCode(-ver)
|
||||||
|
|
||||||
|
|
||||||
|
def isConnected(self):
|
||||||
|
return self.app.IsConnected
|
||||||
|
|
||||||
|
|
||||||
|
def getLibVersion(self):
|
||||||
|
return self.app.LibVersion
|
||||||
|
|
||||||
|
|
||||||
|
def getLibRevision(self):
|
||||||
|
return self.app.LibRevision
|
||||||
|
|
||||||
|
|
||||||
|
def Destroy(self):
|
||||||
|
self.app.TidyUp()
|
||||||
|
if self.events:
|
||||||
|
del self.events
|
||||||
|
del self.app
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
class NotifClasses(object):
|
||||||
|
def __init__(self, classes = []):
|
||||||
|
self.clss = Dispatch("libsnarl25.Classes")
|
||||||
|
for cls in classes:
|
||||||
|
self.add(*cls)
|
||||||
|
|
||||||
|
def count(self):
|
||||||
|
return self.clss.Count()
|
||||||
|
|
||||||
|
def add(self, *cls):
|
||||||
|
self.clss.Add(*cls)
|
||||||
|
return self.clss.Count()
|
||||||
|
|
||||||
|
def remove(self, cls):
|
||||||
|
self.clss.Remove(cls)
|
||||||
|
return self.clss.Count()
|
||||||
|
|
||||||
|
def makeEmpty(self):
|
||||||
|
self.clss.MakeEmpty()
|
||||||
|
return self.clss.Count()
|
||||||
|
|
||||||
|
def Classes(self):
|
||||||
|
return self.clss
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
class Notification(object):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
actions,
|
||||||
|
callbackScript,
|
||||||
|
callbackScriptType,
|
||||||
|
cls,
|
||||||
|
defaultCallback,
|
||||||
|
duration,
|
||||||
|
icon,
|
||||||
|
mergeUID,
|
||||||
|
priority,
|
||||||
|
replaceUID,
|
||||||
|
text,
|
||||||
|
title,
|
||||||
|
uid,
|
||||||
|
):
|
||||||
|
nt = Dispatch("libsnarl25.Notification")
|
||||||
|
nt.Actions = NotifActions(actions).Actions()
|
||||||
|
nt.CallbackScript = callbackScript
|
||||||
|
nt.CallbackScriptType = callbackScriptType
|
||||||
|
nt.Class = cls
|
||||||
|
nt.DefaultCallback = defaultCallback
|
||||||
|
nt.Duration = duration
|
||||||
|
if icon:
|
||||||
|
nt.Icon = icon
|
||||||
|
nt.MergeUID = mergeUID
|
||||||
|
nt.Priority = priority
|
||||||
|
nt.ReplaceUID = replaceUID
|
||||||
|
nt.Text = text
|
||||||
|
nt.Title = title
|
||||||
|
nt.UID = uid
|
||||||
|
self.nt = nt
|
||||||
|
|
||||||
|
def Add(self, name, value, update):
|
||||||
|
self.nt.Add(name, value, True)
|
||||||
|
|
||||||
|
def Note(self):
|
||||||
|
return self.nt
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
class NotifActions(object):
|
||||||
|
def __init__(self, actions=[]):
|
||||||
|
self.actns = Dispatch("libsnarl25.Actions")
|
||||||
|
self.actions = actions
|
||||||
|
for action in actions:
|
||||||
|
self.actns.Add(*action)
|
||||||
|
|
||||||
|
def add(self, actn):
|
||||||
|
self.actns.Add(*actn)
|
||||||
|
self.actions.append(actn)
|
||||||
|
return self.actns.Count()
|
||||||
|
|
||||||
|
def remove(self, actn):
|
||||||
|
if actn in self.actions:
|
||||||
|
ix = self.actions.index(actn)
|
||||||
|
self.actns.Remove(ix + 1)
|
||||||
|
self.actions.pop(ix)
|
||||||
|
return self.actns.Count()
|
||||||
|
|
||||||
|
def makeEmpty(self):
|
||||||
|
self.actns.MakeEmpty()
|
||||||
|
self.actions = []
|
||||||
|
return self.actns.Count()
|
||||||
|
|
||||||
|
def Actions(self):
|
||||||
|
return self.actns
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user