Skip to content
Snippets Groups Projects
Commit 71e495b5 authored by Yann Leboulanger's avatar Yann Leboulanger
Browse files

finish removing plugins

parent a063a0d2
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 2295 deletions
from acronyms_expander import AcronymsExpanderPlugin
# -*- 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/>.
##
'''
Acronyms expander plugin.
:author: Mateusz Biliński <mateusz@bilinski.it>
:since: 9th June 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL
'''
import sys
import gtk
import gobject
from plugins import GajimPlugin
from plugins.helpers import log, log_calls
class AcronymsExpanderPlugin(GajimPlugin):
@log_calls('AcronymsExpanderPlugin')
def init(self):
self.description = _('Replaces acronyms (or other strings) '
'with given expansions/substitutes.')
self.config_dialog = None
self.gui_extension_points = {
'chat_control_base': (self.connect_with_chat_control_base,
self.disconnect_from_chat_control_base)
}
self.config_default_values = {
'INVOKER': (' ', ''),
'ACRONYMS': ({'RTFM': 'Read The Friendly Manual',
'/slap': '/me slaps',
'PS-': 'plug-in system',
'G-': 'Gajim',
'GNT-': 'http://trac.gajim.org/newticket',
'GW-': 'http://trac.gajim.org/',
'GTS-': 'http://trac.gajim.org/report',
},
''),
}
@log_calls('AcronymsExpanderPlugin')
def textbuffer_live_acronym_expander(self, tb):
"""
@param tb gtk.TextBuffer
"""
#assert isinstance(tb,gtk.TextBuffer)
ACRONYMS = self.config['ACRONYMS']
INVOKER = self.config['INVOKER']
t = tb.get_text(tb.get_start_iter(), tb.get_end_iter())
#log.debug('%s %d'%(t, len(t)))
if t and t[-1] == INVOKER:
#log.debug('changing msg text')
base, sep, head=t[:-1].rpartition(INVOKER)
log.debug('%s | %s | %s'%(base, sep, head))
if head in ACRONYMS:
head = ACRONYMS[head]
#log.debug('head: %s'%(head))
t = ''.join((base, sep, head, INVOKER))
#log.debug("setting text: '%s'"%(t))
gobject.idle_add(tb.set_text, t)
@log_calls('AcronymsExpanderPlugin')
def connect_with_chat_control_base(self, chat_control):
d = {}
tv = chat_control.msg_textview
tb = tv.get_buffer()
h_id = tb.connect('changed', self.textbuffer_live_acronym_expander)
d['h_id'] = h_id
chat_control.acronyms_expander_plugin_data = d
return True
@log_calls('AcronymsExpanderPlugin')
def disconnect_from_chat_control_base(self, chat_control):
d = chat_control.acronyms_expander_plugin_data
tv = chat_control.msg_textview
tv.get_buffer().disconnect(d['h_id'])
[info]
name: Acronyms Expander
short_name: acronyms_expander
version: 0.1
description: Replaces acronyms (or other strings) with given expansions/substitutes.
authors: Mateusz Biliński <mateusz@bilinski.it>
homepage: http://blog.bilinski.it
# -*- 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/>.
##
'''
Adjustable chat window banner.
Includes tweaks to make it compact.
Based on patch by pb in ticket #4133:
http://trac.gajim.org/attachment/ticket/4133/gajim-chatbanneroptions-svn10008.patch
:author: Mateusz Biliński <mateusz@bilinski.it>
:since: 30 July 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL
'''
import sys
import gtk
import gobject
import message_control
from common import gajim
from common import helpers
from plugins import GajimPlugin
from plugins.helpers import log, log_calls
from plugins.gui import GajimPluginConfigDialog
class BannerTweaksPlugin(GajimPlugin):
@log_calls('BannerTweaksPlugin')
def init(self):
self.description = _('Allows user to tweak chat window banner '
'appearance (eg. make it compact).\n'
'Based on patch by pb in ticket #4133:\n'
'http://trac.gajim.org/attachment/ticket/4133.')
self.config_dialog = BannerTweaksPluginConfigDialog(self)
self.gui_extension_points = {
'chat_control_base_draw_banner': (self.chat_control_base_draw_banner_called,
self.chat_control_base_draw_banner_deactivation)
}
self.config_default_values = {
'show_banner_image': (True, 'If True, Gajim will display a status icon in the banner of chat windows.'),
'show_banner_online_msg': (True, 'If True, Gajim will display the status message of the contact in the banner of chat windows.'),
'show_banner_resource': (False, 'If True, Gajim will display the resource name of the contact in the banner of chat windows.'),
'banner_small_fonts': (False, 'If True, Gajim will use small fonts for contact name and resource name in the banner of chat windows.'),
'old_chat_avatar_height': (52, 'chat_avatar_height value before plugin was activated'),
}
@log_calls('BannerTweaksPlugin')
def activate(self):
self.config['old_chat_avatar_height'] = gajim.config.get('chat_avatar_height')
#gajim.config.set('chat_avatar_height', 28)
@log_calls('BannerTweaksPlugin')
def deactivate(self):
gajim.config.set('chat_avatar_height', self.config['old_chat_avatar_height'])
@log_calls('BannerTweaksPlugin')
def chat_control_base_draw_banner_called(self, chat_control):
if not self.config['show_banner_online_msg']:
chat_control.banner_status_label.hide()
chat_control.banner_status_label.set_no_show_all(True)
status_text = ''
chat_control.banner_status_label.set_markup(status_text)
if not self.config['show_banner_image']:
if chat_control.TYPE_ID == message_control.TYPE_GC:
banner_status_img = chat_control.xml.get_object(
'gc_banner_status_image')
else:
banner_status_img = chat_control.xml.get_object(
'banner_status_image')
banner_status_img.clear()
# TODO: part below repeats a lot of code from ChatControl.draw_banner_text()
# This could be rewritten using re module: getting markup text from
# banner_name_label and replacing some elements based on plugin config.
# Would it be faster?
if self.config['show_banner_resource'] or self.config['banner_small_fonts']:
banner_name_label = chat_control.xml.get_object('banner_name_label')
label_text = banner_name_label.get_label()
contact = chat_control.contact
jid = contact.jid
name = contact.get_shown_name()
if chat_control.resource:
name += '/' + chat_control.resource
elif contact.resource and self.config['show_banner_resource']:
name += '/' + contact.resource
if chat_control.TYPE_ID == message_control.TYPE_PM:
name = _('%(nickname)s from group chat %(room_name)s') %\
{'nickname': name, 'room_name': chat_control.room_name}
name = gobject.markup_escape_text(name)
# We know our contacts nick, but if another contact has the same nick
# in another account we need to also display the account.
# except if we are talking to two different resources of the same contact
acct_info = ''
for account in gajim.contacts.get_accounts():
if account == chat_control.account:
continue
if acct_info: # We already found a contact with same nick
break
for jid in gajim.contacts.get_jid_list(account):
other_contact_ = \
gajim.contacts.get_first_contact_from_jid(account, jid)
if other_contact_.get_shown_name() == chat_control.contact.get_shown_name():
acct_info = ' (%s)' % \
gobject.markup_escape_text(chat_control.account)
break
font_attrs, font_attrs_small = chat_control.get_font_attrs()
if self.config['banner_small_fonts']:
font_attrs = font_attrs_small
st = gajim.config.get('displayed_chat_state_notifications')
cs = contact.chatstate
if cs and st in ('composing_only', 'all'):
if contact.show == 'offline':
chatstate = ''
elif contact.composing_xep == 'XEP-0085':
if st == 'all' or cs == 'composing':
chatstate = helpers.get_uf_chatstate(cs)
else:
chatstate = ''
elif contact.composing_xep == 'XEP-0022':
if cs in ('composing', 'paused'):
# only print composing, paused
chatstate = helpers.get_uf_chatstate(cs)
else:
chatstate = ''
else:
# When does that happen ? See [7797] and [7804]
chatstate = helpers.get_uf_chatstate(cs)
label_text = '<span %s>%s</span><span %s>%s %s</span>' % \
(font_attrs, name, font_attrs_small, acct_info, chatstate)
else:
# weight="heavy" size="x-large"
label_text = '<span %s>%s</span><span %s>%s</span>' % \
(font_attrs, name, font_attrs_small, acct_info)
banner_name_label.set_markup(label_text)
@log_calls('BannerTweaksPlugin')
def chat_control_base_draw_banner_deactivation(self, chat_control):
pass
#chat_control.draw_banner()
class BannerTweaksPluginConfigDialog(GajimPluginConfigDialog):
def init(self):
self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
'config_dialog.ui')
self.xml = gtk.Builder()
self.xml.set_translation_domain('gajim_plugins')
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
['banner_tweaks_config_vbox'])
self.config_vbox = self.xml.get_object('banner_tweaks_config_vbox')
self.child.pack_start(self.config_vbox)
self.show_banner_image_checkbutton = self.xml.get_object('show_banner_image_checkbutton')
self.show_banner_online_msg_checkbutton = self.xml.get_object('show_banner_online_msg_checkbutton')
self.show_banner_resource_checkbutton = self.xml.get_object('show_banner_resource_checkbutton')
self.banner_small_fonts_checkbutton = self.xml.get_object('banner_small_fonts_checkbutton')
self.xml.connect_signals(self)
def on_run(self):
self.show_banner_image_checkbutton.set_active(self.plugin.config['show_banner_image'])
self.show_banner_online_msg_checkbutton.set_active(self.plugin.config['show_banner_online_msg'])
self.show_banner_resource_checkbutton.set_active(self.plugin.config['show_banner_resource'])
self.banner_small_fonts_checkbutton.set_active(self.plugin.config['banner_small_fonts'])
def on_show_banner_image_checkbutton_toggled(self, button):
self.plugin.config['show_banner_image'] = button.get_active()
def on_show_banner_online_msg_checkbutton_toggled(self, button):
self.plugin.config['show_banner_online_msg'] = button.get_active()
def on_show_banner_resource_checkbutton_toggled(self, button):
self.plugin.config['show_banner_resource'] = button.get_active()
def on_banner_small_fonts_checkbutton_toggled(self, button):
self.plugin.config['banner_small_fonts'] = button.get_active()
from plugin import DBusPlugin
[info]
name: D-Bus Support
short_name: dbus
version: 0.1
description: D-Bus support. Based on remote_control module from
Gajim core but uses new events handling system.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it
# -*- coding: utf-8 -*-
## Copyright (C) 2005-2006 Yann Leboulanger <asterix@lagaule.org>
## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com>
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
## Copyright (C) 2007 Travis Shirk <travis@pobox.com>
## Copyright (C) 2008 Mateusz Biliński <mateusz@bilinski.it>
##
## 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/>.
##
'''
D-BUS Support plugin.
Based on src/remote_control.py
:author: Mateusz Biliński <mateusz@bilinski.it>
:since: 8th August 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL
'''
import os
import new
import gobject
from common import dbus_support
if dbus_support.supported:
import dbus
if dbus_support:
INTERFACE = 'org.gajim.dbusplugin.RemoteInterface'
OBJ_PATH = '/org/gajim/dbusplugin/RemoteObject'
SERVICE = 'org.gajim.dbusplugin'
import dbus.service
import dbus.glib
# type mapping
# in most cases it is a utf-8 string
DBUS_STRING = dbus.String
# general type (for use in dicts, where all values should have the same type)
DBUS_BOOLEAN = dbus.Boolean
DBUS_DOUBLE = dbus.Double
DBUS_INT32 = dbus.Int32
# dictionary with string key and binary value
DBUS_DICT_SV = lambda : dbus.Dictionary({}, signature="sv")
# dictionary with string key and value
DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss")
# empty type (there is no equivalent of None on D-Bus, but historically gajim
# used 0 instead)
DBUS_NONE = lambda : dbus.Int32(0)
def get_dbus_struct(obj):
''' recursively go through all the items and replace
them with their casted dbus equivalents
'''
if obj is None:
return DBUS_NONE()
if isinstance(obj, (unicode, str)):
return DBUS_STRING(obj)
if isinstance(obj, int):
return DBUS_INT32(obj)
if isinstance(obj, float):
return DBUS_DOUBLE(obj)
if isinstance(obj, bool):
return DBUS_BOOLEAN(obj)
if isinstance(obj, (list, tuple)):
result = dbus.Array([get_dbus_struct(i) for i in obj],
signature='v')
if result == []:
return DBUS_NONE()
return result
if isinstance(obj, dict):
result = DBUS_DICT_SV()
for key, value in obj.items():
result[DBUS_STRING(key)] = get_dbus_struct(value)
if result == {}:
return DBUS_NONE()
return result
# unknown type
return DBUS_NONE()
class SignalObject(dbus.service.Object):
''' Local object definition for /org/gajim/dbus/RemoteObject.
(This docstring is not be visible,
because the clients can access only the remote object.)'''
def __init__(self, bus_name):
self.first_show = True
self.vcard_account = None
# register our dbus API
dbus.service.Object.__init__(self, bus_name, OBJ_PATH)
@dbus.service.signal(INTERFACE, signature='av')
def Roster(self, account_and_data):
pass
@dbus.service.signal(INTERFACE, signature='av')
def AccountPresence(self, status_and_account):
pass
@dbus.service.signal(INTERFACE, signature='av')
def ContactPresence(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def ContactAbsence(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def ContactStatus(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def NewMessage(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def Subscribe(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def Subscribed(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def Unsubscribed(self, account_and_jid):
pass
@dbus.service.signal(INTERFACE, signature='av')
def NewAccount(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def VcardInfo(self, account_and_vcard):
pass
@dbus.service.signal(INTERFACE, signature='av')
def LastStatusTime(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def OsInfo(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def GCPresence(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def GCMessage(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def RosterInfo(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def NewGmail(self, account_and_array):
pass
@dbus.service.signal(INTERFACE, signature='av')
def EntityTime(self, account_and_array):
pass
def raise_signal(self, signal, arg):
'''raise a signal, with a single argument of unspecified type
Instead of obj.raise_signal("Foo", bar), use obj.Foo(bar).'''
getattr(self, signal)(arg)
@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
def get_status(self, account):
'''Returns status (show to be exact) which is the global one
unless account is given'''
if not account:
# If user did not ask for account, returns the global status
return DBUS_STRING(helpers.get_global_show())
# return show for the given account
index = gajim.connections[account].connected
return DBUS_STRING(gajim.SHOW_LIST[index])
@dbus.service.method(INTERFACE, in_signature='s', out_signature='s')
def get_status_message(self, account):
'''Returns status which is the global one
unless account is given'''
if not account:
# If user did not ask for account, returns the global status
return DBUS_STRING(str(helpers.get_global_status()))
# return show for the given account
status = gajim.connections[account].status
return DBUS_STRING(status)
def _get_account_and_contact(self, account, jid):
'''get the account (if not given) and contact instance from jid'''
connected_account = None
contact = None
accounts = gajim.contacts.get_accounts()
# if there is only one account in roster, take it as default
# if user did not ask for account
if not account and len(accounts) == 1:
account = accounts[0]
if account:
if gajim.connections[account].connected > 1: # account is connected
connected_account = account
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
else:
for account in accounts:
contact = gajim.contacts.get_contact_with_highest_priority(account,
jid)
if contact and gajim.connections[account].connected > 1:
# account is connected
connected_account = account
break
if not contact:
contact = jid
return connected_account, contact
def _get_account_for_groupchat(self, account, room_jid):
'''get the account which is connected to groupchat (if not given)
or check if the given account is connected to the groupchat'''
connected_account = None
accounts = gajim.contacts.get_accounts()
# if there is only one account in roster, take it as default
# if user did not ask for account
if not account and len(accounts) == 1:
account = accounts[0]
if account:
if gajim.connections[account].connected > 1 and \
room_jid in gajim.gc_connected[account] and \
gajim.gc_connected[account][room_jid]:
# account and groupchat are connected
connected_account = account
else:
for account in accounts:
if gajim.connections[account].connected > 1 and \
room_jid in gajim.gc_connected[account] and \
gajim.gc_connected[account][room_jid]:
# account and groupchat are connected
connected_account = account
break
return connected_account
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
def send_file(self, file_path, jid, account):
'''send file, located at 'file_path' to 'jid', using account
(optional) 'account' '''
jid = self._get_real_jid(jid, account)
connected_account, contact = self._get_account_and_contact(account, jid)
if connected_account:
if file_path[:7] == 'file://':
file_path=file_path[7:]
if os.path.isfile(file_path): # is it file?
gajim.interface.instances['file_transfers'].send_file(
connected_account, contact, file_path)
return DBUS_BOOLEAN(True)
return DBUS_BOOLEAN(False)
def _send_message(self, jid, message, keyID, account, type = 'chat',
subject = None):
'''can be called from send_chat_message (default when send_message)
or send_single_message'''
if not jid or not message:
return DBUS_BOOLEAN(False)
if not keyID:
keyID = ''
connected_account, contact = self._get_account_and_contact(account, jid)
if connected_account:
connection = gajim.connections[connected_account]
connection.send_message(jid, message, keyID, type, subject)
return DBUS_BOOLEAN(True)
return DBUS_BOOLEAN(False)
@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='b')
def send_chat_message(self, jid, message, keyID, account):
'''Send chat 'message' to 'jid', using account (optional) 'account'.
if keyID is specified, encrypt the message with the pgp key '''
jid = self._get_real_jid(jid, account)
return self._send_message(jid, message, keyID, account)
@dbus.service.method(INTERFACE, in_signature='sssss', out_signature='b')
def send_single_message(self, jid, subject, message, keyID, account):
'''Send single 'message' to 'jid', using account (optional) 'account'.
if keyID is specified, encrypt the message with the pgp key '''
jid = self._get_real_jid(jid, account)
return self._send_message(jid, message, keyID, account, type, subject)
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
def send_groupchat_message(self, room_jid, message, account):
'''Send 'message' to groupchat 'room_jid',
using account (optional) 'account'.'''
if not room_jid or not message:
return DBUS_BOOLEAN(False)
connected_account = self._get_account_for_groupchat(account, room_jid)
if connected_account:
connection = gajim.connections[connected_account]
connection.send_gc_message(room_jid, message)
return DBUS_BOOLEAN(True)
return DBUS_BOOLEAN(False)
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
def open_chat(self, jid, account):
'''Shows the tabbed window for new message to 'jid', using account
(optional) 'account' '''
if not jid:
raise MissingArgument
return DBUS_BOOLEAN(False)
jid = self._get_real_jid(jid, account)
try:
jid = helpers.parse_jid(jid)
except:
# Jid is not conform, ignore it
return DBUS_BOOLEAN(False)
if account:
accounts = [account]
else:
accounts = gajim.connections.keys()
if len(accounts) == 1:
account = accounts[0]
connected_account = None
first_connected_acct = None
for acct in accounts:
if gajim.connections[acct].connected > 1: # account is online
contact = gajim.contacts.get_first_contact_from_jid(acct, jid)
if gajim.interface.msg_win_mgr.has_window(jid, acct):
connected_account = acct
break
# jid is in roster
elif contact:
connected_account = acct
break
# we send the message to jid not in roster, because account is
# specified, or there is only one account
elif account:
connected_account = acct
elif first_connected_acct is None:
first_connected_acct = acct
# if jid is not a conntact, open-chat with first connected account
if connected_account is None and first_connected_acct:
connected_account = first_connected_acct
if connected_account:
gajim.interface.new_chat_from_jid(connected_account, jid)
# preserve the 'steal focus preservation'
win = gajim.interface.msg_win_mgr.get_window(jid,
connected_account).window
if win.get_property('visible'):
win.window.focus()
return DBUS_BOOLEAN(True)
return DBUS_BOOLEAN(False)
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
def change_status(self, status, message, account):
''' change_status(status, message, account). account is optional -
if not specified status is changed for all accounts. '''
if status not in ('offline', 'online', 'chat',
'away', 'xa', 'dnd', 'invisible'):
return DBUS_BOOLEAN(False)
if account:
gobject.idle_add(gajim.interface.roster.send_status, account,
status, message)
else:
# account not specified, so change the status of all accounts
for acc in gajim.contacts.get_accounts():
if not gajim.config.get_per('accounts', acc,
'sync_with_global_status'):
continue
gobject.idle_add(gajim.interface.roster.send_status, acc,
status, message)
return DBUS_BOOLEAN(False)
@dbus.service.method(INTERFACE, in_signature='', out_signature='')
def show_next_pending_event(self):
'''Show the window(s) with next pending event in tabbed/group chats.'''
if gajim.events.get_nb_events():
gajim.interface.systray.handle_first_event()
@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{sv}')
def contact_info(self, jid):
'''get vcard info for a contact. Return cached value of the vcard.
'''
if not isinstance(jid, unicode):
jid = unicode(jid)
if not jid:
raise MissingArgument
return DBUS_DICT_SV()
jid = self._get_real_jid(jid)
cached_vcard = gajim.connections.values()[0].get_cached_vcard(jid)
if cached_vcard:
return get_dbus_struct(cached_vcard)
# return empty dict
return DBUS_DICT_SV()
@dbus.service.method(INTERFACE, in_signature='', out_signature='as')
def list_accounts(self):
'''list register accounts'''
result = gajim.contacts.get_accounts()
result_array = dbus.Array([], signature='s')
if result and len(result) > 0:
for account in result:
result_array.append(DBUS_STRING(account))
return result_array
@dbus.service.method(INTERFACE, in_signature='s', out_signature='a{ss}')
def account_info(self, account):
'''show info on account: resource, jid, nick, prio, message'''
result = DBUS_DICT_SS()
if gajim.connections.has_key(account):
# account is valid
con = gajim.connections[account]
index = con.connected
result['status'] = DBUS_STRING(gajim.SHOW_LIST[index])
result['name'] = DBUS_STRING(con.name)
result['jid'] = DBUS_STRING(gajim.get_jid_from_account(con.name))
result['message'] = DBUS_STRING(con.status)
result['priority'] = DBUS_STRING(unicode(con.priority))
result['resource'] = DBUS_STRING(unicode(gajim.config.get_per(
'accounts', con.name, 'resource')))
return result
@dbus.service.method(INTERFACE, in_signature='s', out_signature='aa{sv}')
def list_contacts(self, account):
'''list all contacts in the roster. If the first argument is specified,
then return the contacts for the specified account'''
result = dbus.Array([], signature='aa{sv}')
accounts = gajim.contacts.get_accounts()
if len(accounts) == 0:
return result
if account:
accounts_to_search = [account]
else:
accounts_to_search = accounts
for acct in accounts_to_search:
if acct in accounts:
for jid in gajim.contacts.get_jid_list(acct):
item = self._contacts_as_dbus_structure(
gajim.contacts.get_contacts(acct, jid))
if item:
result.append(item)
return result
@dbus.service.method(INTERFACE, in_signature='', out_signature='')
def toggle_roster_appearance(self):
''' shows/hides the roster window '''
win = gajim.interface.roster.window
if win.get_property('visible'):
gobject.idle_add(win.hide)
else:
win.present()
# preserve the 'steal focus preservation'
if self._is_first():
win.window.focus()
else:
win.window.focus(long(time()))
@dbus.service.method(INTERFACE, in_signature='', out_signature='')
def toggle_ipython(self):
''' shows/hides the ipython window '''
win = gajim.ipython_window
if win:
if win.window.is_visible():
gobject.idle_add(win.hide)
else:
win.show_all()
win.present()
else:
gajim.interface.create_ipython_window()
@dbus.service.method(INTERFACE, in_signature='', out_signature='a{ss}')
def prefs_list(self):
prefs_dict = DBUS_DICT_SS()
def get_prefs(data, name, path, value):
if value is None:
return
key = ''
if path is not None:
for node in path:
key += node + '#'
key += name
prefs_dict[DBUS_STRING(key)] = DBUS_STRING(value[1])
gajim.config.foreach(get_prefs)
return prefs_dict
@dbus.service.method(INTERFACE, in_signature='', out_signature='b')
def prefs_store(self):
try:
gajim.interface.save_config()
except Exception, e:
return DBUS_BOOLEAN(False)
return DBUS_BOOLEAN(True)
@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
def prefs_del(self, key):
if not key:
return DBUS_BOOLEAN(False)
key_path = key.split('#', 2)
if len(key_path) != 3:
return DBUS_BOOLEAN(False)
if key_path[2] == '*':
gajim.config.del_per(key_path[0], key_path[1])
else:
gajim.config.del_per(key_path[0], key_path[1], key_path[2])
return DBUS_BOOLEAN(True)
@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
def prefs_put(self, key):
if not key:
return DBUS_BOOLEAN(False)
key_path = key.split('#', 2)
if len(key_path) < 3:
subname, value = key.split('=', 1)
gajim.config.set(subname, value)
return DBUS_BOOLEAN(True)
subname, value = key_path[2].split('=', 1)
gajim.config.set_per(key_path[0], key_path[1], subname, value)
return DBUS_BOOLEAN(True)
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
def add_contact(self, jid, account):
if account:
if account in gajim.connections and \
gajim.connections[account].connected > 1:
# if given account is active, use it
AddNewContactWindow(account = account, jid = jid)
else:
# wrong account
return DBUS_BOOLEAN(False)
else:
# if account is not given, show account combobox
AddNewContactWindow(account = None, jid = jid)
return DBUS_BOOLEAN(True)
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='b')
def remove_contact(self, jid, account):
jid = self._get_real_jid(jid, account)
accounts = gajim.contacts.get_accounts()
# if there is only one account in roster, take it as default
if account:
accounts = [account]
contact_exists = False
for account in accounts:
contacts = gajim.contacts.get_contacts(account, jid)
if contacts:
gajim.connections[account].unsubscribe(jid)
for contact in contacts:
gajim.interface.roster.remove_contact(contact, account)
gajim.contacts.remove_jid(account, jid)
contact_exists = True
return DBUS_BOOLEAN(contact_exists)
def _is_first(self):
if self.first_show:
self.first_show = False
return True
return False
def _get_real_jid(self, jid, account = None):
'''get the real jid from the given one: removes xmpp: or get jid from nick
if account is specified, search only in this account
'''
if account:
accounts = [account]
else:
accounts = gajim.connections.keys()
if jid.startswith('xmpp:'):
return jid[5:] # len('xmpp:') = 5
nick_in_roster = None # Is jid a nick ?
for account in accounts:
# Does jid exists in roster of one account ?
if gajim.contacts.get_contacts(account, jid):
return jid
if not nick_in_roster:
# look in all contact if one has jid as nick
for jid_ in gajim.contacts.get_jid_list(account):
c = gajim.contacts.get_contacts(account, jid_)
if c[0].name == jid:
nick_in_roster = jid_
break
if nick_in_roster:
# We have not found jid in roster, but we found is as a nick
return nick_in_roster
# We have not found it as jid nor as nick, probably a not in roster jid
return jid
def _contacts_as_dbus_structure(self, contacts):
''' get info from list of Contact objects and create dbus dict '''
if not contacts:
return None
prim_contact = None # primary contact
for contact in contacts:
if prim_contact is None or contact.priority > prim_contact.priority:
prim_contact = contact
contact_dict = DBUS_DICT_SV()
contact_dict['name'] = DBUS_STRING(prim_contact.name)
contact_dict['show'] = DBUS_STRING(prim_contact.show)
contact_dict['jid'] = DBUS_STRING(prim_contact.jid)
if prim_contact.keyID:
keyID = None
if len(prim_contact.keyID) == 8:
keyID = prim_contact.keyID
elif len(prim_contact.keyID) == 16:
keyID = prim_contact.keyID[8:]
if keyID:
contact_dict['openpgp'] = keyID
contact_dict['resources'] = dbus.Array([], signature='(sis)')
for contact in contacts:
resource_props = dbus.Struct((DBUS_STRING(contact.resource),
dbus.Int32(contact.priority), DBUS_STRING(contact.status)))
contact_dict['resources'].append(resource_props)
contact_dict['groups'] = dbus.Array([], signature='(s)')
for group in prim_contact.groups:
contact_dict['groups'].append((DBUS_STRING(group),))
return contact_dict
@dbus.service.method(INTERFACE, in_signature='', out_signature='s')
def get_unread_msgs_number(self):
return DBUS_STRING(str(gajim.events.get_nb_events()))
@dbus.service.method(INTERFACE, in_signature='s', out_signature='b')
def start_chat(self, account):
if not account:
# error is shown in gajim-remote check_arguments(..)
return DBUS_BOOLEAN(False)
NewChatDialog(account)
return DBUS_BOOLEAN(True)
@dbus.service.method(INTERFACE, in_signature='ss', out_signature='')
def send_xml(self, xml, account):
if account:
gajim.connections[account].send_stanza(xml)
else:
for acc in gajim.contacts.get_accounts():
gajim.connections[acc].send_stanza(xml)
@dbus.service.method(INTERFACE, in_signature='ssss', out_signature='')
def join_room(self, room_jid, nick, password, account):
if not account:
# get the first connected account
accounts = gajim.connections.keys()
for acct in accounts:
if gajim.account_is_connected(acct):
account = acct
break
if not account:
return
if not nick:
nick = ''
gajim.interface.instances[account]['join_gc'] = \
JoinGroupchatWindow(account, room_jid, nick)
else:
gajim.interface.join_gc_room(account, room_jid, nick, password)
from common import gajim
from common import helpers
from time import time
from dialogs import AddNewContactWindow, NewChatDialog, JoinGroupchatWindow
from plugins import GajimPlugin
from plugins.helpers import log_calls, log
from common import ged
class DBusPlugin(GajimPlugin):
@log_calls('DBusPlugin')
def init(self):
self.description = _('D-Bus support.'
' Based on remote_control module from'
'\nGajim core but uses new events handling system.')
self.config_dialog = None
#self.gui_extension_points = {}
#self.config_default_values = {}
self.events_names = ['Roster', 'AccountPresence', 'ContactPresence',
'ContactAbsence', 'ContactStatus', 'NewMessage',
'Subscribe', 'Subscribed', 'Unsubscribed',
'NewAccount', 'VcardInfo', 'LastStatusTime',
'OsInfo', 'GCPresence', 'GCMessage', 'RosterInfo',
'NewGmail', 'EntityTime']
self.signal_object = None
self.events_handlers = {}
self._set_handling_methods()
@log_calls('DBusPlugin')
def activate(self):
session_bus = dbus_support.session_bus.SessionBus()
bus_name = dbus.service.BusName(SERVICE, bus=session_bus)
self.signal_object = SignalObject(bus_name)
@log_calls('DBusPlugin')
def deactivate(self):
self.signal_object.remove_from_connection()
self.signal_object = None
@log_calls('DBusPlugin')
def _set_handling_methods(self):
for event_name in self.events_names:
setattr(self, event_name,
new.instancemethod(
self._generate_handling_method(event_name),
self,
DBusPlugin))
self.events_handlers[event_name] = (ged.POSTCORE,
getattr(self, event_name))
def _generate_handling_method(self, event_name):
def handler(self, arg):
#print "Handler of event %s called"%(event_name)
if self.signal_object:
getattr(self.signal_object, event_name)(get_dbus_struct(arg))
return handler
from plugin import EventsDumpPlugin
[info]
name: Events Dump
short_name: events_dump
version: 0.1
description: Dumps info about selected events to console.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it
# -*- 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 Dump plugin.
Dumps info about selected events to console.
:author: Mateusz Biliński <mateusz@bilinski.it>
:since: 10th August 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL
'''
import new
from pprint import pformat
from plugins import GajimPlugin
from plugins.helpers import log_calls, log
from common import ged
class EventsDumpPlugin(GajimPlugin):
@log_calls('EventsDumpPlugin')
def init(self):
self.description = _('Dumps info about selected events to console.')
self.config_dialog = None
#self.gui_extension_points = {}
#self.config_default_values = {}
events_from_old_dbus_support = [
'Roster', 'AccountPresence', 'ContactPresence',
'ContactAbsence', 'ContactStatus', 'NewMessage',
'Subscribe', 'Subscribed', 'Unsubscribed',
'NewAccount', 'VcardInfo', 'LastStatusTime',
'OsInfo', 'GCPresence', 'GCMessage', 'RosterInfo',
'NewGmail']
events_from_src_gajim = [
'ROSTER', 'WARNING', 'ERROR',
'INFORMATION', 'ERROR_ANSWER', 'STATUS',
'NOTIFY', 'MSGERROR', 'MSGSENT', 'MSGNOTSENT',
'SUBSCRIBED', 'UNSUBSCRIBED', 'SUBSCRIBE',
'AGENT_ERROR_INFO', 'AGENT_ERROR_ITEMS',
'AGENT_REMOVED', 'REGISTER_AGENT_INFO',
'AGENT_INFO_ITEMS', 'AGENT_INFO_INFO',
'QUIT', 'NEW_ACC_CONNECTED',
'NEW_ACC_NOT_CONNECTED', 'ACC_OK', 'ACC_NOT_OK',
'MYVCARD', 'VCARD', 'LAST_STATUS_TIME', 'OS_INFO',
'GC_NOTIFY', 'GC_MSG', 'GC_SUBJECT', 'GC_CONFIG',
'GC_CONFIG_CHANGE', 'GC_INVITATION',
'GC_AFFILIATION', 'GC_PASSWORD_REQUIRED',
'BAD_PASSPHRASE', 'ROSTER_INFO', 'BOOKMARKS',
'CON_TYPE', 'CONNECTION_LOST', 'FILE_REQUEST',
'GMAIL_NOTIFY', 'FILE_REQUEST_ERROR',
'FILE_SEND_ERROR', 'STANZA_ARRIVED', 'STANZA_SENT',
'HTTP_AUTH', 'VCARD_PUBLISHED',
'VCARD_NOT_PUBLISHED', 'ASK_NEW_NICK', 'SIGNED_IN',
'METACONTACTS', 'ATOM_ENTRY', 'FAILED_DECRYPT',
'PRIVACY_LISTS_RECEIVED', 'PRIVACY_LIST_RECEIVED',
'PRIVACY_LISTS_ACTIVE_DEFAULT',
'PRIVACY_LIST_REMOVED', 'ZC_NAME_CONFLICT',
'PING_SENT', 'PING_REPLY', 'PING_ERROR',
'SEARCH_FORM', 'SEARCH_RESULT',
'RESOURCE_CONFLICT', 'PEP_CONFIG',
'UNIQUE_ROOM_ID_UNSUPPORTED',
'UNIQUE_ROOM_ID_SUPPORTED', 'SESSION_NEG',
'GPG_PASSWORD_REQUIRED', 'SSL_ERROR',
'FINGERPRINT_ERROR', 'PLAIN_CONNECTION',
'PUBSUB_NODE_REMOVED', 'PUBSUB_NODE_NOT_REMOVED']
network_events_from_core = ['raw-message-received',
'raw-iq-received',
'raw-pres-received']
network_events_generated_in_nec = [
'customized-message-received',
'more-customized-message-received',
'modify-only-message-received',
'enriched-chat-message-received']
self.events_names = []
self.events_names += network_events_from_core
self.events_names += network_events_generated_in_nec
self.events_handlers = {}
self._set_handling_methods()
@log_calls('EventsDumpPlugin')
def activate(self):
pass
@log_calls('EventsDumpPlugin')
def deactivate(self):
pass
@log_calls('EventsDumpPlugin')
def _set_handling_methods(self):
for event_name in self.events_names:
setattr(self, event_name,
new.instancemethod(
self._generate_handling_method(event_name),
self,
EventsDumpPlugin))
self.events_handlers[event_name] = (ged.POSTCORE,
getattr(self, event_name))
def _generate_handling_method(self, event_name):
def handler(self, *args):
print "Event '%s' occured. Arguments: %s\n\n===\n"%(event_name, pformat(args))
return handler
from plugin import NewEventsExamplePlugin
[info]
name: New Events Example
short_name: new_events_example
version: 0.1
description: Shows how to generate new network events based on existing one using Network Events Controller.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it
# -*- 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/>.
##
'''
New Events Example plugin.
Demonstrates how to use Network Events Controller to generate new events
based on existing one.
:author: Mateusz Biliński <mateusz@bilinski.it>
:since: 15th August 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL
'''
import new
from pprint import pformat
from common import helpers
from common import gajim
from plugins import GajimPlugin
from plugins.helpers import log_calls, log
from common import ged
from common import nec
class NewEventsExamplePlugin(GajimPlugin):
@log_calls('NewEventsExamplePlugin')
def init(self):
self.description = _('Shows how to generate new network events based '
'on existing one using Network Events Controller.')
self.config_dialog = None
#self.gui_extension_points = {}
#self.config_default_values = {}
self.events_handlers = {'raw-message-received' :
(ged.POSTCORE, self.raw_message_received),
'customized-message-received' :
(ged.POSTCORE, self.customized_message_received),
'enriched-chat-message-received' :
(ged.POSTCORE, self.enriched_chat_message_received)}
self.events = [CustomizedMessageReceivedEvent,
MoreCustomizedMessageReceivedEvent,
ModifyOnlyMessageReceivedEvent,
EnrichedChatMessageReceivedEvent]
def enriched_chat_message_received(self, event_object):
pass
# print "Event '%s' occured. Event object: %s\n\n===\n" % \
# (event_object.name, event_object)
def raw_message_received(self, event_object):
pass
# print "Event '%s' occured. Event object: %s\n\n===\n" % \
# (event_object.name,event_object)
def customized_message_received(self, event_object):
pass
# print "Event '%s' occured. Event object: %s\n\n===\n" % \
# (event_object.name, event_object
@log_calls('NewEventsExamplePlugin')
def activate(self):
pass
@log_calls('NewEventsExamplePlugin')
def deactivate(self):
pass
class CustomizedMessageReceivedEvent(nec.NetworkIncomingEvent):
name = 'customized-message-received'
base_network_events = ['raw-message-received']
def generate(self):
return True
class MoreCustomizedMessageReceivedEvent(nec.NetworkIncomingEvent):
'''
Shows chain of custom created events.
This one is based on custom 'customized-messsage-received'.
'''
name = 'more-customized-message-received'
base_network_events = ['customized-message-received']
def generate(self):
return True
class ModifyOnlyMessageReceivedEvent(nec.NetworkIncomingEvent):
name = 'modify-only-message-received'
base_network_events = ['raw-message-received']
def generate(self):
msg_type = self.base_event.stanza.attrs.get('type', None)
if msg_type == u'chat':
msg_text = ''.join(self.base_event.stanza.kids[0].data)
self.base_event.stanza.kids[0].setData(
u'%s [MODIFIED BY CUSTOM NETWORK EVENT]' % (msg_text))
return False
class EnrichedChatMessageReceivedEvent(nec.NetworkIncomingEvent):
'''
Generates more friendly (in use by handlers) network event for
received chat message.
'''
name = 'enriched-chat-message-received'
base_network_events = ['raw-message-received']
def generate(self):
msg_type = self.base_event.stanza.attrs.get('type', None)
if msg_type == u'chat':
self.stanza = self.base_event.stanza
self.conn = self.base_event.conn
self.from_jid = helpers.get_full_jid_from_iq(self.stanza)
self.from_jid_without_resource = gajim.get_jid_without_resource(
self.from_jid)
self.account = self.conn.name
self.from_nickname = gajim.get_contact_name_from_jid( self.account,
self.from_jid_without_resource)
self.msg_text = ''.join(self.stanza.kids[0].data)
return True
return False
__all__ = ['RosterButtonsPlugin']
from plugin import RosterButtonsPlugin
[info]
name: Roster Buttons
short_name: roster_buttons
version: 0.1
description: Adds quick action buttons to roster window.
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it
# -*- 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/>.
##
'''
Roster buttons plug-in.
:author: Mateusz Biliński <mateusz@bilinski.it>
:since: 14th June 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:license: GPL
'''
import sys
import gtk
from common import gajim
from plugins import GajimPlugin
from plugins.helpers import log, log_calls
class RosterButtonsPlugin(GajimPlugin):
@log_calls('RosterButtonsPlugin')
def init(self):
self.description = _('Adds quick action buttons to roster window.')
self.GTK_BUILDER_FILE_PATH = self.local_file_path('roster_buttons.ui')
self.roster_vbox = gajim.interface.roster.xml.get_object('roster_vbox2')
self.show_offline_contacts_menuitem = gajim.interface.roster.xml.get_object('show_offline_contacts_menuitem')
self.config_dialog = None
@log_calls('RosterButtonsPlugin')
def activate(self):
self.xml = gtk.Builder()
self.xml.set_translation_domain('gajim_plugins')
self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
['roster_buttons_buttonbox'])
self.buttonbox = self.xml.get_object('roster_buttons_buttonbox')
self.roster_vbox.pack_start(self.buttonbox, expand=False)
self.roster_vbox.reorder_child(self.buttonbox, 0)
self.xml.connect_signals(self)
@log_calls('RosterButtonsPlugin')
def deactivate(self):
self.roster_vbox.remove(self.buttonbox)
self.buttonbox = None
self.xml = None
@log_calls('RosterButtonsPlugin')
def on_roster_button_1_clicked(self, button):
#gajim.interface.roster.on_show_offline_contacts_menuitem_activate(None)
self.show_offline_contacts_menuitem.set_active(not self.show_offline_contacts_menuitem.get_active())
@log_calls('RosterButtonsPlugin')
def on_roster_button_2_clicked(self, button):
pass
@log_calls('RosterButtonsPlugin')
def on_roster_button_3_clicked(self, button):
pass
@log_calls('RosterButtonsPlugin')
def on_roster_button_4_clicked(self, button):
pass
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkWindow" id="window1">
<child>
<object class="GtkHButtonBox" id="roster_buttons_buttonbox">
<property name="visible">True</property>
<property name="homogeneous">True</property>
<property name="layout_style">spread</property>
<child>
<object class="GtkButton" id="roster_button_1">
<property name="label">1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_roster_button_1_clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="roster_button_2">
<property name="label">2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_roster_button_2_clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="roster_button_3">
<property name="label">3</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_roster_button_3_clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="roster_button_4">
<property name="label">4</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_roster_button_4_clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
"""
A python version of the main functions to use Snarl
(http://www.fullphat.net/snarl)
Version 1.0
This module can be used in two ways. One is the normal way
the other snarl interfaces work. This means you can call snShowMessage
and get an ID back for manipulations.
The other way is there is a class this module exposes called SnarlMessage.
This allows you to keep track of the message as a python object. If you
use the send without specifying False as the argument it will set the ID
to what the return of the last SendMessage was. This is of course only
useful for the SHOW message.
Requires one of:
pywin32 extensions from http://pywin32.sourceforge.net
ctypes (included in Python 2.5, downloadable for earlier versions)
Creator: Sam Listopad II (samlii@users.sourceforge.net)
Copyright 2006-2008 Samuel Listopad II
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
"""
import array, struct
def LOWORD(dword):
"""Return the low WORD of the passed in integer"""
return dword & 0x0000ffff
#get the hi word
def HIWORD(dword):
"""Return the high WORD of the passed in integer"""
return dword >> 16
class Win32FuncException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class Win32Funcs:
"""Just a little class to hide the details of finding and using the
correct win32 functions. The functions may throw a UnicodeEncodeError if
there is not a unicode version and it is sent a unicode string that cannot
be converted to ASCII."""
WM_USER = 0x400
WM_COPYDATA = 0x4a
#Type of String the functions are expecting.
#Used like function(myWin32Funcs.strType(param)).
__strType = str
#FindWindow function to use
__FindWindow = None
#FindWindow function to use
__FindWindowEx = None
#SendMessage function to use
__SendMessage = None
#SendMessageTimeout function to use
__SendMessageTimeout = None
#IsWindow function to use
__IsWindow = None
#RegisterWindowMessage to use
__RegisterWindowMessage = None
#GetWindowText to use
__GetWindowText = None
def FindWindow(self, lpClassName, lpWindowName):
"""Wraps the windows API call of FindWindow"""
if lpClassName is not None:
lpClassName = self.__strType(lpClassName)
if lpWindowName is not None:
lpWindowName = self.__strType(lpWindowName)
return self.__FindWindow(lpClassName, lpWindowName)
def FindWindowEx(self, hwndParent, hwndChildAfter, lpClassName, lpWindowName):
"""Wraps the windows API call of FindWindow"""
if lpClassName is not None:
lpClassName = self.__strType(lpClassName)
if lpWindowName is not None:
lpWindowName = self.__strType(lpWindowName)
return self.__FindWindowEx(hwndParent, hwndChildAfter, lpClassName, lpWindowName)
def SendMessage(self, hWnd, Msg, wParam, lParam):
"""Wraps the windows API call of SendMessage"""
return self.__SendMessage(hWnd, Msg, wParam, lParam)
def SendMessageTimeout(self, hWnd, Msg,
wParam, lParam, fuFlags,
uTimeout, lpdwResult = None):
"""Wraps the windows API call of SendMessageTimeout"""
idToRet = None
try:
idFromMsg = array.array('I', [0])
result = idFromMsg.buffer_info()[0]
response = self.__SendMessageTimeout(hWnd, Msg, wParam,
lParam, fuFlags,
uTimeout, result)
if response == 0:
raise Win32FuncException, "SendMessageTimeout TimedOut"
idToRet = idFromMsg[0]
except TypeError:
idToRet = self.__SendMessageTimeout(hWnd, Msg, wParam,
lParam, fuFlags,
uTimeout)
if lpdwResult is not None and lpdwResult.typecode == 'I':
lpdwResult[0] = idToRet
return idToRet
def IsWindow(self, hWnd):
"""Wraps the windows API call of IsWindow"""
return self.__IsWindow(hWnd)
def RegisterWindowMessage(self, lpString):
"""Wraps the windows API call of RegisterWindowMessage"""
return self.__RegisterWindowMessage(self.__strType(lpString))
def GetWindowText(self, hWnd, lpString = None, nMaxCount = None):
"""Wraps the windows API call of SendMessageTimeout"""
text = ''
if hWnd == 0:
return text
if nMaxCount is None:
nMaxCount = 1025
try:
arrayType = 'c'
if self.__strType == unicode:
arrayType = 'u'
path_string = array.array(arrayType, self.__strType('\x00') * nMaxCount)
path_buffer = path_string.buffer_info()[0]
result = self.__GetWindowText(hWnd,
path_buffer,
nMaxCount)
if result > 0:
if self.__strType == unicode:
text = path_string[0:result].tounicode()
else:
text = path_string[0:result].tostring()
except TypeError:
text = self.__GetWindowText(hWnd)
if lpString is not None and lpString.typecode == 'c':
lpdwResult[0:len(text)] = array.array('c', str(text));
if lpString is not None and lpString.typecode == 'u':
lpdwResult[0:len(text)] = array.array('u', unicode(text));
return text
def __init__(self):
"""Load up my needed functions"""
# First see if they already have win32gui imported. If so use it.
# This has to be checked first since the auto check looks for ctypes
# first.
try:
self.__FindWindow = win32gui.FindWindow
self.__FindWindowEx = win32gui.FindWindowEx
self.__GetWindowText = win32gui.GetWindowText
self.__IsWindow = win32gui.IsWindow
self.__SendMessage = win32gui.SendMessage
self.__SendMessageTimeout = win32gui.SendMessageTimeout
self.__RegisterWindowMessage = win32gui.RegisterWindowMessage
self.__strType = unicode
#Something threw a NameError, most likely the win32gui lines
#so do auto check
except NameError:
try:
from ctypes import windll
self.__FindWindow = windll.user32.FindWindowW
self.__FindWindowEx = windll.user32.FindWindowExW
self.__GetWindowText = windll.user32.GetWindowTextW
self.__IsWindow = windll.user32.IsWindow
self.__SendMessage = windll.user32.SendMessageW
self.__SendMessageTimeout = windll.user32.SendMessageTimeoutW
self.__RegisterWindowMessage = windll.user32.RegisterWindowMessageW
self.__strType = unicode
#FindWindowW wasn't found, look for FindWindowA
except AttributeError:
try:
self.__FindWindow = windll.user32.FindWindowA
self.__FindWindowEx = windll.user32.FindWindowExA
self.__GetWindowText = windll.user32.GetWindowTextA
self.__IsWindow = windll.user32.IsWindow
self.__SendMessage = windll.user32.SendMessageA
self.__SendMessageTimeout = windll.user32.SendMessageTimeoutA
self.__RegisterWindowMessage = windll.user32.RegisterWindowMessageA
# Couldn't find either so Die and tell user why.
except AttributeError:
import sys
sys.stderr.write("Your Windows TM setup seems to be corrupt."+
" No FindWindow found in user32.\n")
sys.stderr.flush()
sys.exit(3)
except ImportError:
try:
import win32gui
self.__FindWindow = win32gui.FindWindow
self.__FindWindowEx = win32gui.FindWindowEx
self.__GetWindowText = win32gui.GetWindowText
self.__IsWindow = win32gui.IsWindow
self.__SendMessage = win32gui.SendMessage
self.__SendMessageTimeout = win32gui.SendMessageTimeout
self.__RegisterWindowMessage = win32gui.RegisterWindowMessage
self.__strType = unicode
except ImportError:
import sys
sys.stderr.write("You need to have either"+
" ctypes or pywin32 installed.\n")
sys.stderr.flush()
#sys.exit(2)
myWin32Funcs = Win32Funcs()
SHOW = 1
HIDE = 2
UPDATE = 3
IS_VISIBLE = 4
GET_VERSION = 5
REGISTER_CONFIG_WINDOW = 6
REVOKE_CONFIG_WINDOW = 7
REGISTER_ALERT = 8
REVOKE_ALERT = 9
REGISTER_CONFIG_WINDOW_2 = 10
GET_VERSION_EX = 11
SET_TIMEOUT = 12
EX_SHOW = 32
GLOBAL_MESSAGE = "SnarlGlobalMessage"
GLOBAL_MSG = "SnarlGlobalEvent"
#Messages That may be received from Snarl
SNARL_LAUNCHED = 1
SNARL_QUIT = 2
SNARL_ASK_APPLET_VER = 3
SNARL_SHOW_APP_UI = 4
SNARL_NOTIFICATION_CLICKED = 32 #notification was right-clicked by user
SNARL_NOTIFICATION_CANCELLED = SNARL_NOTIFICATION_CLICKED #Name clarified
SNARL_NOTIFICATION_TIMED_OUT = 33
SNARL_NOTIFICATION_ACK = 34 #notification was left-clicked by user
#Snarl Test Message
WM_SNARLTEST = myWin32Funcs.WM_USER + 237
M_ABORTED = 0x80000007L
M_ACCESS_DENIED = 0x80000009L
M_ALREADY_EXISTS = 0x8000000CL
M_BAD_HANDLE = 0x80000006L
M_BAD_POINTER = 0x80000005L
M_FAILED = 0x80000008L
M_INVALID_ARGS = 0x80000003L
M_NO_INTERFACE = 0x80000004L
M_NOT_FOUND = 0x8000000BL
M_NOT_IMPLEMENTED = 0x80000001L
M_OK = 0x00000000L
M_OUT_OF_MEMORY = 0x80000002L
M_TIMED_OUT = 0x8000000AL
ErrorCodeRev = {
0x80000007L : "M_ABORTED",
0x80000009L : "M_ACCESS_DENIED",
0x8000000CL : "M_ALREADY_EXISTS",
0x80000006L : "M_BAD_HANDLE",
0x80000005L : "M_BAD_POINTER",
0x80000008L : "M_FAILED",
0x80000003L : "M_INVALID_ARGS",
0x80000004L : "M_NO_INTERFACE",
0x8000000BL : "M_NOT_FOUND",
0x80000001L : "M_NOT_IMPLEMENTED",
0x00000000L : "M_OK",
0x80000002L : "M_OUT_OF_MEMORY",
0x8000000AL : "M_TIMED_OUT"
}
class SnarlMessage(object):
"""The main Snarl interface object.
ID = Snarl Message ID for most operations. See SDK for more info
as to other values to put here.
type = Snarl Message Type. Valid values are : SHOW, HIDE, UPDATE,
IS_VISIBLE, GET_VERSION, REGISTER_CONFIG_WINDOW, REVOKE_CONFIG_WINDOW
all which are constants in the PySnarl module.
timeout = Timeout in seconds for the Snarl Message
data = Snarl Message data. This is dependant upon message type. See SDK
title = Snarl Message title.
text = Snarl Message text.
icon = Path to the icon to display in the Snarl Message.
"""
__msgType = 0
__msgID = 0
__msgTimeout = 0
__msgData = 0
__msgTitle = ""
__msgText = ""
__msgIcon = ""
__msgClass = ""
__msgExtra = ""
__msgExtra2 = ""
__msgRsvd1 = 0
__msgRsvd2 = 0
__msgHWnd = 0
lastKnownHWnd = 0
def getType(self):
"""Type Attribute getter."""
return self.__msgType
def setType(self, value):
"""Type Attribute setter."""
if( isinstance(value, (int, long)) ):
self.__msgType = value
type = property(getType, setType, doc="The Snarl Message Type")
def getID(self):
"""ID Attribute getter."""
return self.__msgID
def setID(self, value):
"""ID Attribute setter."""
if( isinstance(value, (int, long)) ):
self.__msgID = value
ID = property(getID, setID, doc="The Snarl Message ID")
def getTimeout(self):
"""Timeout Attribute getter."""
return self.__msgTimeout
def updateTimeout(self, value):
"""Timeout Attribute setter."""
if( isinstance(value, (int, long)) ):
self.__msgTimeout = value
timeout = property(getTimeout, updateTimeout,
doc="The Snarl Message Timeout")
def getData(self):
"""Data Attribute getter."""
return self.__msgData
def setData(self, value):
"""Data Attribute setter."""
if( isinstance(value, (int, long)) ):
self.__msgData = value
data = property(getData, setData, doc="The Snarl Message Data")
def getTitle(self):
"""Title Attribute getter."""
return self.__msgTitle
def setTitle(self, value):
"""Title Attribute setter."""
if( isinstance(value, basestring) ):
self.__msgTitle = value
title = property(getTitle, setTitle, doc="The Snarl Message Title")
def getText(self):
"""Text Attribute getter."""
return self.__msgText
def setText(self, value):
"""Text Attribute setter."""
if( isinstance(value, basestring) ):
self.__msgText = value
text = property(getText, setText, doc="The Snarl Message Text")
def getIcon(self):
"""Icon Attribute getter."""
return self.__msgIcon
def setIcon(self, value):
"""Icon Attribute setter."""
if( isinstance(value, basestring) ):
self.__msgIcon = value
icon = property(getIcon, setIcon, doc="The Snarl Message Icon")
def getClass(self):
"""Class Attribute getter."""
return self.__msgClass
def setClass(self, value):
"""Class Attribute setter."""
if( isinstance(value, basestring) ):
self.__msgClass = value
msgclass = property(getClass, setClass, doc="The Snarl Message Class")
def getExtra(self):
"""Extra Attribute getter."""
return self.__msgExtra
def setExtra(self, value):
"""Extra Attribute setter."""
if( isinstance(value, basestring) ):
self.__msgExtra = value
extra = property(getExtra, setExtra, doc="Extra Info for the Snarl Message")
def getExtra2(self):
"""Extra2 Attribute getter."""
return self.__msgExtra2
def setExtra2(self, value):
"""Extra2 Attribute setter."""
if( isinstance(value, basestring) ):
self.__msgExtra2 = value
extra2 = property(getExtra2, setExtra2,
doc="More Extra Info for the Snarl Message")
def getRsvd1(self):
"""Rsvd1 Attribute getter."""
return self.__msgRsvd1
def setRsvd1(self, value):
"""Rsvd1 Attribute setter."""
if( isinstance(value, (int, long)) ):
self.__msgRsvd1 = value
rsvd1 = property(getRsvd1, setRsvd1, doc="The Snarl Message Field Rsvd1")
def getRsvd2(self):
"""Rsvd2 Attribute getter."""
return self.__msgRsvd2
def setRsvd2(self, value):
"""Rsvd2 Attribute setter."""
if( isinstance(value, (int, long)) ):
self.__msgRsvd2 = value
rsvd2 = property(getRsvd2, setRsvd2, doc="The Snarl Message Field Rsvd2")
def getHwnd(self):
"""hWnd Attribute getter."""
return self.__msgHWnd
def setHwnd(self, value):
"""hWnd Attribute setter."""
if( isinstance(value, (int, long)) ):
self.__msgHWnd = value
hWnd = property(getHwnd, setHwnd, doc="The hWnd of the window this message is being sent from")
def __init__(self, title="", text="", icon="", msg_type=1, msg_id=0):
self.__msgTimeout = 0
self.__msgData = 0
self.__msgClass = ""
self.__msgExtra = ""
self.__msgExtra2 = ""
self.__msgRsvd1 = 0
self.__msgRsvd2 = 0
self.__msgType = msg_type
self.__msgText = text
self.__msgTitle = title
self.__msgIcon = icon
self.__msgID = msg_id
def createCopyStruct(self):
"""Creates the struct to send as the copyData in the message."""
return struct.pack("ILLL1024s1024s1024s1024s1024s1024sLL",
self.__msgType,
self.__msgID,
self.__msgTimeout,
self.__msgData,
self.__msgTitle.encode('utf-8'),
self.__msgText.encode('utf-8'),
self.__msgIcon.encode('utf-8'),
self.__msgClass.encode('utf-8'),
self.__msgExtra.encode('utf-8'),
self.__msgExtra2.encode('utf-8'),
self.__msgRsvd1,
self.__msgRsvd2
)
__lpData = None
__cds = None
def packData(self, dwData):
"""This packs the data in the necessary format for a
WM_COPYDATA message."""
self.__lpData = None
self.__cds = None
item = self.createCopyStruct()
self.__lpData = array.array('c', item)
lpData_ad = self.__lpData.buffer_info()[0]
cbData = self.__lpData.buffer_info()[1]
self.__cds = array.array('c',
struct.pack("IIP",
dwData,
cbData,
lpData_ad)
)
cds_ad = self.__cds.buffer_info()[0]
return cds_ad
def reset(self):
"""Reset this SnarlMessage to the default state."""
self.__msgType = 0
self.__msgID = 0
self.__msgTimeout = 0
self.__msgData = 0
self.__msgTitle = ""
self.__msgText = ""
self.__msgIcon = ""
self.__msgClass = ""
self.__msgExtra = ""
self.__msgExtra2 = ""
self.__msgRsvd1 = 0
self.__msgRsvd2 = 0
def send(self, setid=True):
"""Send this SnarlMessage to the Snarl window.
Args:
setid - Boolean defining whether or not to set the ID
of this SnarlMessage to the return value of
the SendMessage call. Default is True to
make simple case of SHOW easy.
"""
hwnd = myWin32Funcs.FindWindow(None, "Snarl")
if myWin32Funcs.IsWindow(hwnd):
if self.type == REGISTER_CONFIG_WINDOW or self.type == REGISTER_CONFIG_WINDOW_2:
self.hWnd = self.data
try:
response = myWin32Funcs.SendMessageTimeout(hwnd,
myWin32Funcs.WM_COPYDATA,
self.hWnd, self.packData(2),
2, 500)
except Win32FuncException:
return False
idFromMsg = response
if setid:
self.ID = idFromMsg
return True
else:
return idFromMsg
print "No snarl window found"
return False
def hide(self):
"""Hide this message. Type will revert to type before calling hide
to allow for better reuse of object."""
oldType = self.__msgType
self.__msgType = HIDE
retVal = bool(self.send(False))
self.__msgType = oldType
return retVal
def isVisible(self):
"""Is this message visible. Type will revert to type before calling
hide to allow for better reuse of object."""
oldType = self.__msgType
self.__msgType = IS_VISIBLE
retVal = bool(self.send(False))
self.__msgType = oldType
return retVal
def update(self, title=None, text=None, icon=None):
"""Update this message with given title and text. Type will revert
to type before calling hide to allow for better reuse of object."""
oldType = self.__msgType
self.__msgType = UPDATE
if text:
self.__msgText = text
if title:
self.__msgTitle = title
if icon:
self.__msgIcon = icon
retVal = self.send(False)
self.__msgType = oldType
return retVal
def setTimeout(self, timeout):
"""Set the timeout in seconds of the message"""
oldType = self.__msgType
oldData = self.__msgData
self.__msgType = SET_TIMEOUT
#self.timeout = timeout
#self.__msgData = self.__msgTimeout
self.__msgData = timeout
retVal = self.send(False)
self.__msgType = oldType
self.__msgData = oldData
return retVal
def show(self, timeout=None, title=None,
text=None, icon=None,
replyWindow=None, replyMsg=None, msgclass=None, soundPath=None):
"""Show a message"""
oldType = self.__msgType
oldTimeout = self.__msgTimeout
self.__msgType = SHOW
if text:
self.__msgText = text
if title:
self.__msgTitle = title
if timeout:
self.__msgTimeout = timeout
if icon:
self.__msgIcon = icon
if replyWindow:
self.__msgID = replyMsg
if replyMsg:
self.__msgData = replyWindow
if soundPath:
self.__msgExtra = soundPath
if msgclass:
self.__msgClass = msgclass
if ((self.__msgClass and self.__msgClass != "") or
(self.__msgExtra and self.__msgExtra != "")):
self.__msgType = EX_SHOW
retVal = bool(self.send())
self.__msgType = oldType
self.__msgTimeout = oldTimeout
return retVal
def snGetVersion():
""" Get the version of Snarl that is running as a tuple. (Major, Minor)
If Snarl is not running or there was an error it will
return False."""
msg = SnarlMessage(msg_type=GET_VERSION)
version = msg.send(False)
if not version:
return False
return (HIWORD(version), LOWORD(version))
def snGetVersionEx():
""" Get the internal version of Snarl that is running.
If Snarl is not running or there was an error it will
return False."""
sm = SnarlMessage(msg_type=GET_VERSION_EX)
verNum = sm.send(False)
if not verNum:
return False
return verNum
def snGetGlobalMessage():
"""Get the Snarl global message id from windows."""
return myWin32Funcs.RegisterWindowMessage(GLOBAL_MSG)
def snShowMessage(title, text, timeout=0, iconPath="",
replyWindow=0, replyMsg=0):
"""Show a message using Snarl and return its ID. See SDK for arguments."""
sm = SnarlMessage( title, text, iconPath, msg_id=replyMsg)
sm.data = replyWindow
if sm.show(timeout):
return sm.ID
else:
return False
def snShowMessageEx(msgClass, title, text, timeout=0, iconPath="",
replyWindow=0, replyMsg=0, soundFile=None, hWndFrom=None):
"""Show a message using Snarl and return its ID. See SDK for arguments.
One added argument is hWndFrom that allows one to make the messages appear
to come from a specific window. This window should be the one you registered
earlier with RegisterConfig"""
sm = SnarlMessage( title, text, iconPath, msg_id=replyMsg)
sm.data = replyWindow
if hWndFrom is not None:
sm.hWnd = hWndFrom
else:
sm.hWnd = SnarlMessage.lastKnownHWnd
if sm.show(timeout, msgclass=msgClass, soundPath=soundFile):
return sm.ID
else:
return False
def snUpdateMessage(msgId, msgTitle, msgText, icon=None):
"""Update a message"""
sm = SnarlMessage(msg_id=msgId)
if icon:
sm.icon = icon
return sm.update(msgTitle, msgText)
def snHideMessage(msgId):
"""Hide a message"""
return SnarlMessage(msg_id=msgId).hide()
def snSetTimeout(msgId, timeout):
"""Update the timeout of a message already shown."""
sm = SnarlMessage(msg_id=msgId)
return sm.setTimeout(timeout)
def snIsMessageVisible(msgId):
"""Returns True if the message is visible False otherwise."""
return SnarlMessage(msg_id=msgId).isVisible()
def snRegisterConfig(replyWnd, appName, replyMsg):
"""Register a config window. See SDK for more info."""
global lastRegisteredSnarlMsg
sm = SnarlMessage(msg_type=REGISTER_CONFIG_WINDOW,
title=appName,
msg_id=replyMsg)
sm.data = replyWnd
SnarlMessage.lastKnownHWnd = replyWnd
return sm.send(False)
def snRegisterConfig2(replyWnd, appName, replyMsg, icon):
"""Register a config window. See SDK for more info."""
global lastRegisteredSnarlMsg
sm = SnarlMessage(msg_type=REGISTER_CONFIG_WINDOW_2,
title=appName,
msg_id=replyMsg,
icon=icon)
sm.data = replyWnd
SnarlMessage.lastKnownHWnd = replyWnd
return sm.send(False)
def snRegisterAlert(appName, classStr) :
"""Register an alert for an already registered config. See SDK for more info."""
sm = SnarlMessage(msg_type=REGISTER_ALERT,
title=appName,
text=classStr)
return sm.send(False)
def snRevokeConfig(replyWnd):
"""Revoke a config window"""
sm = SnarlMessage(msg_type=REVOKE_CONFIG_WINDOW)
sm.data = replyWnd
if replyWnd == SnarlMessage.lastKnownHWnd:
SnarlMessage.lastKnownHWnd = 0
return sm.send(False)
def snGetSnarlWindow():
"""Returns the hWnd of the snarl window"""
return myWin32Funcs.FindWindow(None, "Snarl")
def snGetAppPath():
"""Returns the application path of the currently running snarl window"""
app_path = None
snarl_handle = snGetSnarlWindow()
if snarl_handle != 0:
pathwin_handle = myWin32Funcs.FindWindowEx(snarl_handle,
0,
"static",
None)
if pathwin_handle != 0:
try:
result = myWin32Funcs.GetWindowText(pathwin_handle)
app_path = result
except Win32FuncException:
pass
return app_path
def snGetIconsPath():
"""Returns the path to the icons of the program"""
s = snGetAppPath()
if s is None:
return ""
else:
return s + "etc\\icons\\"
def snSendTestMessage(data=None):
"""Sends a test message to Snarl. Used to make sure the
api is connecting"""
param = 0
command = 0
if data:
param = struct.pack("I", data)
command = 1
myWin32Funcs.SendMessage(snGetSnarlWindow(), WM_SNARLTEST, command, param)
from plugin import SnarlNotificationsPlugin
[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://code.google.com/p/pysnarl/).
authors = Mateusz Biliński <mateusz@bilinski.it>
homepage = http://blog.bilinski.it
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment