~jconti/recent-notifications/trunk

47 by Jason Conti
Did some refactoring of files and names.
1
"""
2
Main.py
3
by Jason Conti
4
February 19, 2010
5
6
Applet for viewing recent notifications.
7
"""
8
49 by Jason Conti
Replaced the button text with icons.
9
import gnomeapplet
47 by Jason Conti
Did some refactoring of files and names.
10
import gtk
127 by Jason Conti
The size-allocate signal was not properly updating with the panel size. Found the change-size signal, and now the icon gets properly resized when the panel size changes.
11
import logging
47 by Jason Conti
Did some refactoring of files and names.
12
import os.path
13
81 by Jason Conti
Adding support for gettext translations and a pointless en_US translation as an example. Using distutils-extra to automatically build the translations and the bonobo server. Replaced the build_servers target with update_prefix. This performs basically the same as build_servers except that it will do the substitution on any .in file, and it just writes the output file without the .in, instead of adding it to the data file install list.
14
from string import Template
15
47 by Jason Conti
Did some refactoring of files and names.
16
from About import show_about
139 by Jason Conti
Fixed several bugs in Config and it is now used to read the blacklist.
17
from Config import Config
76 by Jason Conti
Adding icon caching. Since there should be relatively few different icons appearing in the message window, they are now cached in the Icon module. The cache is cleared when the message window is cleared.
18
from Icon import clear_icon_cache, load_icon
129 by Jason Conti
Testing a new panel button. Instead of the previous ToggleButton with an image, this is just an image in an EventBox. It fixes an annoying bug where the ToggleButton has a border that I can't seem to get rid of, that causes the button to be larger than the panel. This results in there being a gap between the popup window (or the context menu) and the panel. I could fix it for the window (but probably not the context menu), by possibly messing with the values in the window alignment method, but there doesn't seem to be a nice way to figure out where it should be. Either way it won't fix the context menu. Still needs to display the current toggled state, but this can probably be solved by adding two more images. Going to play with it for a while first and see. May revert to ToggleButton.
19
from ImageToggleButton import ImageToggleButton
47 by Jason Conti
Did some refactoring of files and names.
20
from MessageWindow import MessageWindow
61 by Jason Conti
Renamed Monitor.py to Notification.py
21
from Notification import Notification
141 by Jason Conti
Added a preferences dialog to enable/disable application blacklists.
22
from Preferences import show_preferences
119 by Jason Conti
Replaced N_ with ngettext so xgettext can find it without having to add --keyword arguments. Updated the pot file.
23
from Translations import _, ngettext
47 by Jason Conti
Did some refactoring of files and names.
24
127 by Jason Conti
The size-allocate signal was not properly updating with the panel size. Found the change-size signal, and now the icon gets properly resized when the panel size changes.
25
logger = logging.getLogger("Main")
26
47 by Jason Conti
Did some refactoring of files and names.
27
class Main(object):
28
  """The main applet wrapper."""
29
  def __init__(self, applet, iid):
30
    self._applet = applet
128 by Jason Conti
Fixed a bug that caused the applet background not to match the panel background. The fix is odd, in that the applet sets its background widget to itself. Found in clock.c.
31
    self._applet.set_background_widget(applet)
127 by Jason Conti
The size-allocate signal was not properly updating with the panel size. Found the change-size signal, and now the icon gets properly resized when the panel size changes.
32
    self._applet.connect("change-size", self.on_change_size)
131 by Jason Conti
When adding the set_selected code to ImageToggleButton, I also added a bit of padding to the left and right of the button so that it was easier to click. The problem is, left and right change when the panel's orientation changes. So added set_orient, to set the proper padding depending on orientation, and added a change-orient callback to the main applet to update the orientation as it changes. Now there are no gaps when the panel is on the left or the right.
33
    self._applet.connect("change-orient", self.on_change_orient)
47 by Jason Conti
Did some refactoring of files and names.
34
35
    self._unread_messages = 0
155 by Jason Conti
Added an optional message count label in the applet.
36
    self._show_count = False
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
37
127 by Jason Conti
The size-allocate signal was not properly updating with the panel size. Found the change-size signal, and now the icon gets properly resized when the panel size changes.
38
    self._applet_size = self.get_applet_size()
39
40
    icon_size = self.get_icon_size(self._applet_size)
41
    self.load_icons(icon_size)
47 by Jason Conti
Did some refactoring of files and names.
42
129 by Jason Conti
Testing a new panel button. Instead of the previous ToggleButton with an image, this is just an image in an EventBox. It fixes an annoying bug where the ToggleButton has a border that I can't seem to get rid of, that causes the button to be larger than the panel. This results in there being a gap between the popup window (or the context menu) and the panel. I could fix it for the window (but probably not the context menu), by possibly messing with the values in the window alignment method, but there doesn't seem to be a nice way to figure out where it should be. Either way it won't fix the context menu. Still needs to display the current toggled state, but this can probably be solved by adding two more images. Going to play with it for a while first and see. May revert to ToggleButton.
43
    self._button = ImageToggleButton()
44
    self._button.set_from_pixbuf(self._read_icon)
131 by Jason Conti
When adding the set_selected code to ImageToggleButton, I also added a bit of padding to the left and right of the button so that it was easier to click. The problem is, left and right change when the panel's orientation changes. So added set_orient, to set the proper padding depending on orientation, and added a change-orient callback to the main applet to update the orientation as it changes. Now there are no gaps when the panel is on the left or the right.
45
    self._button.set_orient(self.get_orient())
47 by Jason Conti
Did some refactoring of files and names.
46
    self._button.connect("toggled", self.on_button_toggled)
155 by Jason Conti
Added an optional message count label in the applet.
47
    self._button.show()
160 by Jason Conti
Moved the unread message label to the toggle button, so that it will be highlighted when the button is clicked.
48
    self._applet.add(self._button)
47 by Jason Conti
Did some refactoring of files and names.
49
81 by Jason Conti
Adding support for gettext translations and a pointless en_US translation as an example. Using distutils-extra to automatically build the translations and the bonobo server. Replaced the build_servers target with update_prefix. This performs basically the same as build_servers except that it will do the substitution on any .in file, and it just writes the output file without the .in, instead of adding it to the data file install list.
50
    self._applet.setup_menu(Template("""
47 by Jason Conti
Did some refactoring of files and names.
51
      <popup name="button3">
81 by Jason Conti
Adding support for gettext translations and a pointless en_US translation as an example. Using distutils-extra to automatically build the translations and the bonobo server. Replaced the build_servers target with update_prefix. This performs basically the same as build_servers except that it will do the substitution on any .in file, and it just writes the output file without the .in, instead of adding it to the data file install list.
52
        <menuitem name="Clear" verb="Clear" _label="$clear_label" pixtype="stock" pixname="gtk-clear"/>
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
53
        <separator/>
81 by Jason Conti
Adding support for gettext translations and a pointless en_US translation as an example. Using distutils-extra to automatically build the translations and the bonobo server. Replaced the build_servers target with update_prefix. This performs basically the same as build_servers except that it will do the substitution on any .in file, and it just writes the output file without the .in, instead of adding it to the data file install list.
54
        <menuitem name="About" verb="About" _label="$about_label" pixtype="stock" pixname="gtk-about"/>
141 by Jason Conti
Added a preferences dialog to enable/disable application blacklists.
55
        <menuitem name="Preferences" verb="Preferences" _label="$preferences_label" pixtype="stock" pixname="gtk-preferences"/>
47 by Jason Conti
Did some refactoring of files and names.
56
      </popup>
81 by Jason Conti
Adding support for gettext translations and a pointless en_US translation as an example. Using distutils-extra to automatically build the translations and the bonobo server. Replaced the build_servers target with update_prefix. This performs basically the same as build_servers except that it will do the substitution on any .in file, and it just writes the output file without the .in, instead of adding it to the data file install list.
57
      """).substitute(
58
          about_label=_("_About"), 
141 by Jason Conti
Added a preferences dialog to enable/disable application blacklists.
59
          clear_label=_("_Clear Messages"),
60
          preferences_label=_("_Preferences")), [
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
61
      ("Clear", lambda a, b: self.on_clear_messages(a)),
141 by Jason Conti
Added a preferences dialog to enable/disable application blacklists.
62
      ("About", lambda a, b: self.on_show_about(a)),
63
      ("Preferences", lambda a, b: self.on_show_preferences(a))
47 by Jason Conti
Did some refactoring of files and names.
64
      ])
65
66
    self._window = MessageWindow(self)
67
68
    self._applet.connect("destroy", self.on_applet_destroyed)
156 by Jason Conti
Fixed a bunch of bugs with the new applet display code.
69
    self._applet.show_all()
47 by Jason Conti
Did some refactoring of files and names.
70
49 by Jason Conti
Replaced the button text with icons.
71
    self.update()
72
139 by Jason Conti
Fixed several bugs in Config and it is now used to read the blacklist.
73
    self._blacklist = Config("~/.config/recent-notifications/blacklist")
137 by Jason Conti
Adding an option to blacklist notifications based on app_name. Applications to be blacklisted should be listed in the file ~/.config/recent-notifications/blacklist, one app_name per line. The app_names are case-sensitive and are listed in the notifications as "from app_name" such as "from Gwibber" or "from Pidgin". They can also be found in ~/.cache/recent-notifications.log on the app_name lines. Thanks to Dinero Francis for reporting the issue.
74
144 by Jason Conti
Can now enable/disable debug messages (which are logged to ~/.cache/recent-notifications.log). Errors are still logged to that file even if debug is disabled. Disabling debug by default, since most people will have no use for it, and if you never reboot, the file could grow quite large.
75
    self._preferences = Config("~/.config/recent-notifications/preferences")
76
    self._preferences.set_if_unset("debug", False)
145 by Jason Conti
Implemented the message limit preference. This required a change to marking the messages as read. Previously, iters to unread items were saved, and then just those iters were marked as unread. I was always a bit wary of this, because I wasn't sure what would happen if I got a stale iter. Well, I found out. The app segfaults. This seems like a bug in GTK, but either way, I decided to stop saving iters. Under the assumption that only the first n messages will be unread, and there are no gaps (which should be correct), the app is now looping through the iters until it finds one that is already read (or runs out).
77
    self._preferences.set_if_unset("message_limit", 0)
155 by Jason Conti
Added an optional message count label in the applet.
78
    self._preferences.set_if_unset("show_count", False)
144 by Jason Conti
Can now enable/disable debug messages (which are logged to ~/.cache/recent-notifications.log). Errors are still logged to that file even if debug is disabled. Disabling debug by default, since most people will have no use for it, and if you never reboot, the file could grow quite large.
79
    self._preferences.add_listener("debug", self.on_preference_change)
145 by Jason Conti
Implemented the message limit preference. This required a change to marking the messages as read. Previously, iters to unread items were saved, and then just those iters were marked as unread. I was always a bit wary of this, because I wasn't sure what would happen if I got a stale iter. Well, I found out. The app segfaults. This seems like a bug in GTK, but either way, I decided to stop saving iters. Under the assumption that only the first n messages will be unread, and there are no gaps (which should be correct), the app is now looping through the iters until it finds one that is already read (or runs out).
80
    self._preferences.add_listener("message_limit", self.on_preference_change)
155 by Jason Conti
Added an optional message count label in the applet.
81
    self._preferences.add_listener("show_count", self.on_preference_change)
144 by Jason Conti
Can now enable/disable debug messages (which are logged to ~/.cache/recent-notifications.log). Errors are still logged to that file even if debug is disabled. Disabling debug by default, since most people will have no use for it, and if you never reboot, the file could grow quite large.
82
    self._preferences.notify_all()
83
61 by Jason Conti
Renamed Monitor.py to Notification.py
84
    self._notify = Notification()
139 by Jason Conti
Fixed several bugs in Config and it is now used to read the blacklist.
85
    self._notify.set_blacklist(self._blacklist)
61 by Jason Conti
Renamed Monitor.py to Notification.py
86
    self._notify.connect("message-received", self.on_message_received)
47 by Jason Conti
Did some refactoring of files and names.
87
166 by Jason Conti
Update applet icons when theme changes.
88
    self._theme = gtk.icon_theme_get_default()
89
    self._theme.connect("changed", self.on_theme_changed)
90
140 by Jason Conti
Added a message context menu item to blacklist the selected application.
91
  def add_to_blacklist(self, app_name):
92
    """Adds the given app_name to the blacklist."""
93
    self._blacklist.set(app_name, True)
94
141 by Jason Conti
Added a preferences dialog to enable/disable application blacklists.
95
  def get_blacklist_items(self):
96
    """Returns a list of (app_name, boolean) tuples for the blacklist items."""
97
    result = []
98
    for key in self._blacklist:
99
      result.append((key, self._blacklist.get_bool(key)))
100
    return result
101
144 by Jason Conti
Can now enable/disable debug messages (which are logged to ~/.cache/recent-notifications.log). Errors are still logged to that file even if debug is disabled. Disabling debug by default, since most people will have no use for it, and if you never reboot, the file could grow quite large.
102
  def set_debug(self, debug):
103
    """Enables/disables debug messages."""
104
    global_logger = logging.getLogger("")
105
    if debug:
106
      global_logger.setLevel(logging.DEBUG)
107
    else:
108
      global_logger.setLevel(logging.ERROR)
109
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
110
  def get_applet_size(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
111
    """Gets the size of the applet."""
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
112
    return self._applet.get_size()
113
114
  def get_icon_size(self, size):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
115
    """Gets the icon size from the given size."""
49 by Jason Conti
Replaced the button text with icons.
116
    if size < 22:
117
      size = 16
118
    elif size < 24:
119
      size = 22
120
    elif size < 32:
121
      size = 24
122
    elif size < 48:
123
      size = 32
124
    else:
125
      size = 48
126
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
127
    return size
49 by Jason Conti
Replaced the button text with icons.
128
47 by Jason Conti
Did some refactoring of files and names.
129
  def get_orient(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
130
    """Gets the orientation of the panel."""
47 by Jason Conti
Did some refactoring of files and names.
131
    return self._applet.get_orient()
132
133
  def get_origin(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
134
    """Gets the position of the button window."""
47 by Jason Conti
Did some refactoring of files and names.
135
    return self._button.get_window().get_origin()
136
137
  def get_screen(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
138
    """Gets the screen the button window is on."""
47 by Jason Conti
Did some refactoring of files and names.
139
    return self._button.get_window().get_screen()
140
141
  def get_size(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
142
    """Gets the size of the button window."""
47 by Jason Conti
Did some refactoring of files and names.
143
    return self._button.get_window().get_size()
144
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
145
  def load_icons(self, size):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
146
    """Loads icons from the default icon theme."""
113 by Jason Conti
Adding new panel icons to better match the ubuntu humanity theme. Moved to lucid so removed the code to build karmic packages, since I can't test them at the moment.
147
    self._read_icon = load_icon("humanity-notification-read", size)
148
    self._unread_icon = load_icon("humanity-notification-unread", size)
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
149
49 by Jason Conti
Replaced the button text with icons.
150
  def update(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
151
    """Updates the applet icon and unread messages tooltip."""
49 by Jason Conti
Replaced the button text with icons.
152
    self.update_applet_image()
153
    self.update_unread_messages()
154
155
  def update_applet_image(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
156
    """Update the applet icon if it has changed."""
49 by Jason Conti
Replaced the button text with icons.
157
    if self._unread_messages > 0:
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
158
      icon = self._unread_icon
49 by Jason Conti
Replaced the button text with icons.
159
    else:
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
160
      icon = self._read_icon
161
129 by Jason Conti
Testing a new panel button. Instead of the previous ToggleButton with an image, this is just an image in an EventBox. It fixes an annoying bug where the ToggleButton has a border that I can't seem to get rid of, that causes the button to be larger than the panel. This results in there being a gap between the popup window (or the context menu) and the panel. I could fix it for the window (but probably not the context menu), by possibly messing with the values in the window alignment method, but there doesn't seem to be a nice way to figure out where it should be. Either way it won't fix the context menu. Still needs to display the current toggled state, but this can probably be solved by adding two more images. Going to play with it for a while first and see. May revert to ToggleButton.
162
    if icon != self._button.get_pixbuf():
163
      self._button.set_from_pixbuf(icon)
49 by Jason Conti
Replaced the button text with icons.
164
47 by Jason Conti
Did some refactoring of files and names.
165
  def update_unread_messages(self):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
166
    """Updates the unread message tooltip."""
118 by Jason Conti
Just realized I have been incorrectly handling plural forms in the translations. Adding N_ to Translations.py mapped to lngettext. Updated several plural instances to use N_ instead of _ with if/else constructs.
167
    n = self._unread_messages
119 by Jason Conti
Replaced N_ with ngettext so xgettext can find it without having to add --keyword arguments. Updated the pot file.
168
    label = ngettext("1 unread message", "{0} unread messages", n).format(n)
49 by Jason Conti
Replaced the button text with icons.
169
    self._button.set_tooltip_text(label)
160 by Jason Conti
Moved the unread message label to the toggle button, so that it will be highlighted when the button is clicked.
170
    if self._show_count:
171
      self._button.set_label(str(n))
47 by Jason Conti
Did some refactoring of files and names.
172
153 by Jason Conti
Experiment with hiding the message window when it loses focus.
173
  def show_window(self):
174
    """Shows the applet window"""
175
    self._button.set_has_tooltip(False)
176
    self._window.show_dropdown()
177
178
  def hide_window(self):
179
    """Hides the applet window"""
180
    self._button.set_has_tooltip(True)
181
    self._window.hide_dropdown()
182
    self._unread_messages = 0
183
    self.update()
184
47 by Jason Conti
Did some refactoring of files and names.
185
  # Callbacks
186
127 by Jason Conti
The size-allocate signal was not properly updating with the panel size. Found the change-size signal, and now the icon gets properly resized when the panel size changes.
187
  def on_change_size(self, applet, size):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
188
    """Update the icon size if the panel size changes."""
127 by Jason Conti
The size-allocate signal was not properly updating with the panel size. Found the change-size signal, and now the icon gets properly resized when the panel size changes.
189
    if self._applet_size == size:
190
      return
191
192
    self._applet_size = size
193
    icon_size = self.get_icon_size(size)
194
    self.load_icons(icon_size)
195
    self.update_applet_image()
51 by Jason Conti
Moved the icon loading code to Icon.py and changed the behavior of the applet icon, so that new icons are only loaded if the size of the applet changes.
196
131 by Jason Conti
When adding the set_selected code to ImageToggleButton, I also added a bit of padding to the left and right of the button so that it was easier to click. The problem is, left and right change when the panel's orientation changes. So added set_orient, to set the proper padding depending on orientation, and added a change-orient callback to the main applet to update the orientation as it changes. Now there are no gaps when the panel is on the left or the right.
197
  def on_change_orient(self, applet, orient):
153 by Jason Conti
Experiment with hiding the message window when it loses focus.
198
    """Updates the button orientation when the panel changes orientation"""
131 by Jason Conti
When adding the set_selected code to ImageToggleButton, I also added a bit of padding to the left and right of the button so that it was easier to click. The problem is, left and right change when the panel's orientation changes. So added set_orient, to set the proper padding depending on orientation, and added a change-orient callback to the main applet to update the orientation as it changes. Now there are no gaps when the panel is on the left or the right.
199
    self._button.set_orient(orient)
200
201
  def on_applet_destroyed(self, applet):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
202
    """Stop the message notifications before destroying the applet."""
61 by Jason Conti
Renamed Monitor.py to Notification.py
203
    self._notify.close()
47 by Jason Conti
Did some refactoring of files and names.
204
131 by Jason Conti
When adding the set_selected code to ImageToggleButton, I also added a bit of padding to the left and right of the button so that it was easier to click. The problem is, left and right change when the panel's orientation changes. So added set_orient, to set the proper padding depending on orientation, and added a change-orient callback to the main applet to update the orientation as it changes. Now there are no gaps when the panel is on the left or the right.
205
  def on_button_toggled(self, button):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
206
    """Show/Hide the message window when the button is toggled."""
47 by Jason Conti
Did some refactoring of files and names.
207
    if button.get_active():
153 by Jason Conti
Experiment with hiding the message window when it loses focus.
208
      self.show_window()
47 by Jason Conti
Did some refactoring of files and names.
209
    else:
153 by Jason Conti
Experiment with hiding the message window when it loses focus.
210
      self.hide_window()
47 by Jason Conti
Did some refactoring of files and names.
211
131 by Jason Conti
When adding the set_selected code to ImageToggleButton, I also added a bit of padding to the left and right of the button so that it was easier to click. The problem is, left and right change when the panel's orientation changes. So added set_orient, to set the proper padding depending on orientation, and added a change-orient callback to the main applet to update the orientation as it changes. Now there are no gaps when the panel is on the left or the right.
212
  def on_clear_messages(self, item):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
213
    """Clear messages from the message window."""
214
    self._window.clear_messages()
76 by Jason Conti
Adding icon caching. Since there should be relatively few different icons appearing in the message window, they are now cached in the Icon module. The cache is cleared when the message window is cleared.
215
    clear_icon_cache()
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
216
47 by Jason Conti
Did some refactoring of files and names.
217
  def on_message_received(self, monitor, message):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
218
    """Received a message from the notifier."""
137 by Jason Conti
Adding an option to blacklist notifications based on app_name. Applications to be blacklisted should be listed in the file ~/.config/recent-notifications/blacklist, one app_name per line. The app_names are case-sensitive and are listed in the notifications as "from app_name" such as "from Gwibber" or "from Pidgin". They can also be found in ~/.cache/recent-notifications.log on the app_name lines. Thanks to Dinero Francis for reporting the issue.
219
    self._window.add_message(message)
220
    self._unread_messages += 1
221
    self.update()
47 by Jason Conti
Did some refactoring of files and names.
222
131 by Jason Conti
When adding the set_selected code to ImageToggleButton, I also added a bit of padding to the left and right of the button so that it was easier to click. The problem is, left and right change when the panel's orientation changes. So added set_orient, to set the proper padding depending on orientation, and added a change-orient callback to the main applet to update the orientation as it changes. Now there are no gaps when the panel is on the left or the right.
223
  def on_show_about(self, item):
75 by Jason Conti
Adding an option to the context menu to clear the message window. Adding more docstrings to Main.py.
224
    """Show the about dialog."""
47 by Jason Conti
Did some refactoring of files and names.
225
    show_about(self)
226
141 by Jason Conti
Added a preferences dialog to enable/disable application blacklists.
227
  def on_show_preferences(self, item):
228
    """Show the preferences dialog."""
229
    show_preferences(self)
230
144 by Jason Conti
Can now enable/disable debug messages (which are logged to ~/.cache/recent-notifications.log). Errors are still logged to that file even if debug is disabled. Disabling debug by default, since most people will have no use for it, and if you never reboot, the file could grow quite large.
231
  def on_preference_change(self, key, value):
232
    """Triggers actions on preference changes."""
233
    if key == "debug":
234
      self.set_debug(self._preferences.get_bool(key, False))
145 by Jason Conti
Implemented the message limit preference. This required a change to marking the messages as read. Previously, iters to unread items were saved, and then just those iters were marked as unread. I was always a bit wary of this, because I wasn't sure what would happen if I got a stale iter. Well, I found out. The app segfaults. This seems like a bug in GTK, but either way, I decided to stop saving iters. Under the assumption that only the first n messages will be unread, and there are no gaps (which should be correct), the app is now looping through the iters until it finds one that is already read (or runs out).
235
    elif key == "message_limit":
236
      self._window.set_message_limit(self._preferences.get_int(key, 0))
155 by Jason Conti
Added an optional message count label in the applet.
237
    elif key == "show_count":
160 by Jason Conti
Moved the unread message label to the toggle button, so that it will be highlighted when the button is clicked.
238
      self._show_count = self._preferences.get_bool(key, False)
239
      if self._show_count:
240
        self.update()
155 by Jason Conti
Added an optional message count label in the applet.
241
      else:
160 by Jason Conti
Moved the unread message label to the toggle button, so that it will be highlighted when the button is clicked.
242
        self._button.set_label("")
144 by Jason Conti
Can now enable/disable debug messages (which are logged to ~/.cache/recent-notifications.log). Errors are still logged to that file even if debug is disabled. Disabling debug by default, since most people will have no use for it, and if you never reboot, the file could grow quite large.
243
166 by Jason Conti
Update applet icons when theme changes.
244
  def on_theme_changed(self, theme):
245
    """Updates applet icons when the theme changes"""
246
    clear_icon_cache()
247
    icon_size = self.get_icon_size(self._applet_size)
248
    self.load_icons(icon_size)
249
    self.update_applet_image()
250