File: tc_notification.py

package info (click to toggle)
torchat 0.9.9.550-2
  • links: PTS
  • area: main
  • in suites: wheezy
  • size: 772 kB
  • sloc: python: 5,527; makefile: 45; sh: 5
file content (185 lines) | stat: -rw-r--r-- 6,352 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import wx
import config
import os
import subprocess
import threading
import time
import textwrap


# notification_method = gtknotify
#
# should be available when GTK+ is installed
def notificationWindow_gtknotify(mw, name, text, buddy):
    import pynotify
    import cgi
    if not pynotify.is_initted():
        if not pynotify.init('torchat'):
            raise Exception('gtknotify not supported')
    pynotify.Notification(
        cgi.escape(name).encode('ascii', 'xmlcharrefreplace'), 
        cgi.escape(text).encode('ascii', 'xmlcharrefreplace')
    ).show()


# notification_method = knotify
#
# works with KDE4 (maybe somebody could tell me
# how to make this work with KDE3 also)
def notificationWindow_knotify(mw, name, text, buddy):
    import dbus
    knotify = dbus.SessionBus().get_object("org.kde.knotify", "/Notify")
    knotify.event('warning', 'kde', [], name, text,
            [], [], 0, 0, dbus_interface='org.kde.KNotify')


# notification_method = growlnotify
#
# this is meant for Mac OS X where growl is used by many
# other apps. You need to have growl and growlnotify
def notificationWindow_growlnotify(mw, name, text, buddy):
    # This seems to fail about half the time
    # iconpath = os.path.join(config.ICON_DIR, "torchat.png")
    #args = ['growlnotify', '-m', text, '--image', iconpath]
    text = "%s\n\n%s" % (name, text)
    args = ['growlnotify', '-m', text]
    subprocess.Popen(args).communicate()


# notification_method = xosd
#
# this needs python-osd installed on the system
# and works only on the X Window System
def notificationWindow_xosd(mw, name, text, buddy):
    NotificationWindowXosd(mw, name, text, buddy).start()

class NotificationWindowXosd(threading.Thread):
    def __init__(self, mw, name, text, buddy):
        threading.Thread.__init__(self)
        self.name = name.encode("utf-8")
        self.text = text.encode("utf-8")
        
    def run(self):    
        import pyosd
        text = "%s\n%s" % (self.name, self.text)
        text_lines = textwrap.fill(text, 40).split(os.linesep)
        osd = pyosd.osd(lines=len(text_lines), shadow=2, colour="#FFFF00")
        line_number = 0
        for text_line in text_lines:
            osd.display(text_line, line=line_number)
            line_number += 1
        time.sleep(3)


# notification_method = generic
#
# this is the default and works everywhere
def notificationWindow_generic(mw, name, text, buddy):
    NotificationWindowGeneric(mw, name, text, buddy)

class NotificationWindowGeneric(wx.Frame):
    def __init__(self, mw, name, text, buddy):
        wx.Frame.__init__(self, mw,
            style=wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.STAY_ON_TOP)
        self.panel = wx.Panel(self, style=wx.SIMPLE_BORDER)
        self.panel.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK))
        sizer = wx.BoxSizer()
        self.panel.SetSizer(sizer)

        if buddy.profile_avatar_object <> None:
            bitmap = buddy.profile_avatar_object
        else:
            bitmap = wx.Bitmap(os.path.join(config.ICON_DIR, "torchat.png"), wx.BITMAP_TYPE_PNG)
        static_image = wx.StaticBitmap(self.panel, -1, bitmap)
        sizer.Add(static_image, 0, wx.ALL, 5 )

        self.label = wx.StaticText(self.panel)
        self.label.SetLabel("%s\n\n%s" % (name, text))
        sizer.Add(self.label, 0, wx.ALL, 5 )

        wsizer = wx.BoxSizer()
        wsizer.Add(self.panel, 0, wx.ALL, 0)
        self.SetSizerAndFit(wsizer)
        self.Layout()

        # initialize animation
        cx, cy, maxx, maxy = wx.ClientDisplayRect()
        self.w, self.h = self.GetSize()
        self.x_end = maxx - self.w - 20
        self.y_end = maxy - self.h - 20

        self.x_pos = -self.w
        self.y_pos = self.y_end
        self.phase = 0

        self.SetPosition((self.x_pos, self.y_pos))
        
        # the following will prevent the focus 
        # stealing on windows
        self.Disable()
        self.Show()
        self.Enable()

        self.timer = wx.Timer(self, -1)
        self.Bind(wx.EVT_TIMER, self.onTimer)

        # start animation
        self.timer.Start(10, True)


    def onTimer(self, evt):
        if self.phase == 0:
            if self.x_pos < self.x_end:
                # move right and restart timer
                speed = ((self.x_end - self.x_pos) ^ 2) / 10
                self.x_pos += (1 + speed)
                self.SetPosition((self.x_pos, self.y_pos))
                self.timer.Start(10, True)
                return
            else:
                # we are at the right border.
                # now switch phase and wait a bit
                self.phase = 1
                self.timer.Start(3000, True)
                
                # and from now on we also close on mouse contact
                self.panel.Bind(wx.EVT_MOUSE_EVENTS, self.onMouse)
                return

        if self.phase == 1:
            if self.y_pos > -self.h:
                # move upwards and restart timer
                speed = ((self.y_end - self.y_pos) ^ 2) / 10
                self.y_pos -= (5 + speed)
                self.SetPosition((self.x_pos, self.y_pos))
                self.timer.Start(10, True)
                return
            else:
                # we reached the end of the animation
                self.Hide()
                self.Destroy()
        
    def onMouse(self, evt):
        # restart the timer to immediately end the waiting
        self.timer.Start(10, True)


def notificationWindow(mw, name, text, buddy):
    method = config.get('gui', 'notification_method')
    try:
        function = globals()["notificationWindow_%s" % method]
    except:
        print "(1) notification method '%s' is not implemented, falling back to 'generic'." % method
        notificationWindow_generic(mw, name, text, buddy)
        return
    
    try:
        function(mw, name, text, buddy)
    except:
        print "(1) exception while using notification method '%s'" % method
        print "(1) falling back to 'generic'. Traceback follows:"
        config.tb()
        notificationWindow_generic(mw, name, text, buddy)


# vim: set tw=0 sts=4 sw=4 expandtab: