This file is indexed.

/usr/share/pyshared/quodlibet/qltk/notif.py is in exfalso 2.3.2-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# -*- coding: utf-8 -*-
# Copyright 2010 Steven Robertson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.

"""
This module will provide a unified notification area for informational
messages and active tasks. This will eventually handle interactions with
active tasks (e.g. pausing a copooled task), and provide shortcuts for
copooling or threading a task with a status notification. It will also provide
the UI for the planned global undo feature.

Of course, right now it does none of these things.
"""

# This module is still experimental and may change or be removed.

# TODO: Make copooling things with notifications easier (optional)
# TODO: Make Ex Falso use this
# TODO: Port WaitLoadWindow to use this (and not block)
# TODO: Port Media browser to use this
# TODO: Port Download Manager to use this
# TODO: Add basic notification support
# TODO: Add notification history
# TODO: Add notification button/callback support (prereq for global undo)
# TODO: Optimize performance (deferred signals, etc)

import gobject
import gtk
import pango
import traceback

from quodlibet.util import copool

SIZE = gtk.ICON_SIZE_MENU

class ParentProperty(object):
    """
    A property which provides a thin layer of protection against accidental
    reparenting: you must first 'unparent' an instance by setting this
    property to 'None' before you can set a new parent.
    """
    def __get__(self, inst, owner):
        return getattr(inst, '_parent', None)
    def __set__(self, inst, value):
        if getattr(inst, '_parent', None) is not None and value is not None:
            raise ValueError("Cannot set parent property without first "
                    "setting it to 'None'.")
        inst._parent = value

class Task(object):
    def __init__(self, source, desc, known_length=True, controller=None,
                 pause=None, stop=None):
        self.source = source
        self.desc = desc
        if known_length:
            self.frac = 0.
        else:
            self.frac = None
        if controller:
            self.controller = controller
        else:
            self.controller = TaskController.default_instance
        self._pause = pause
        self._stop = stop
        self.pausable = bool(pause)
        self.stoppable = bool(stop)
        self._paused = False
        self.controller.add_task(self)

    def update(self, frac):
        """
        Update a task's progress.
        """
        self.frac = frac
        self.controller.update()

    def pulse(self):
        """
        Indicate progress on a task of unknown length.
        """
        self.update(None)

    def finish(self):
        """
        Mark a task as finished, and remove it from the list of active tasks.
        """
        self.frac = 1.0
        self.controller.finish(self)

    def __set_paused(self, value):
        if self.pausable:
            self._pause(value)
            self._paused = value
    paused = property(lambda self: self._paused, __set_paused)

    def stop(self):
        if self._stop:
            self._stop()
        self.finish()

    def gen(self, gen):
        """
        Act as a generator pass-through, updating and finishing the task's
        progress automatically. If 'gen' has a __len__ property, it will be
        used to set the fraction accordingly.
        """
        try:
            if hasattr(gen, '__len__'):
                for i, x in enumerate(gen):
                    self.update(float(i)/len(gen))
                    yield x
            else:
                for x in gen:
                    yield x
        finally:
            self.finish()

    def list(self, l):
        """
        Evaluates the iterable argument before passing to 'gen'.
        """
        return self.gen(list(l))

    def copool(self, funcid, pause=True, stop=True):
        """
        Convenience function: set the Task's 'pause' and 'stop' callbacks to
        act upon the copool with the given funcid.
        """
        if pause:
            def pause_func(state):
                if state != self._paused:
                    if state:
                        copool.pause(funcid)
                    else:
                        copool.resume(funcid)
            self._pause = pause_func
            self.pausable = True
        if stop:
            self._stop = lambda: copool.remove(funcid)
            self.stoppable = True

    # Support context managers:
    # >>> with Task(...) as t:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.finish()
        return False

class TaskController(object):
    """
    Controller logic for displaying and managing a list of Tasks. Also
    implements the full Task interface to act as a pass-through or summary of
    all tasks in flight on this controller.
    """
    parent = ParentProperty()
    default_instance = None

    def __init__(self):
        self.active_tasks = []
        self._parent = None
        self.update()

    def add_task(self, task):
        self.active_tasks.append(task)
        self.update()

    @property
    def source(self):
        if len(self.active_tasks) == 1:
            return self.active_tasks[0].source
        return _("Active tasks")

    @property
    def desc(self):
        if len(self.active_tasks) == 1:
            return self.active_tasks[0].desc
        self.desc = _("%d tasks running") % len(self.active_tasks)

    @property
    def frac(self):
        fracs = [t.frac for t in self.active_tasks if t.frac is not None]
        if fracs:
            return sum(fracs) / len(self.active_tasks)
        return None

    def __set_paused(self, val):
        for t in self.active_tasks:
            if t.pausable:
                t.paused = val
    def __get_paused(self):
        pausable = [t for t in self.active_tasks if t.pausable]
        if not pausable: return False
        return not [t for t in pausable if not t.paused]
    paused = property(__get_paused, __set_paused)

    def stop(self):
        [t.stop() for t in self.active_tasks if t.stoppable]

    @property
    def pausable(self):
        return [t for t in self.active_tasks if t.pausable]

    @property
    def stoppable(self):
        return [t for t in self.active_tasks if t.stoppable]

    def update(self):
        if self._parent is not None:
            self._parent.update()

    def finish(self, finished_task):
        self.active_tasks = filter(lambda t: t is not finished_task,
                                   self.active_tasks)
        self.update()

# Oh so deliciously hacky.
TaskController.default_instance = TaskController()

class TaskWidget(gtk.HBox):
    """
    Displays a task.
    """
    def __init__(self, task):
        super(TaskWidget, self).__init__()
        self.task = task
        self.label = gtk.Label()
        self.label.set_alignment(1.0, 0.5)
        self.label.set_ellipsize(pango.ELLIPSIZE_END)
        self.pack_start(self.label, padding=12)
        self.progress = gtk.ProgressBar()
        self.progress.set_size_request(200, -1)
        self.pack_start(self.progress, expand=False)
        self.pause = gtk.ToggleButton()
        self.pause.add(gtk.image_new_from_stock(gtk.STOCK_MEDIA_PAUSE, SIZE))
        self.pause.connect('toggled', self.__pause_toggled)
        self.pack_start(self.pause, expand=False)
        self.stop = gtk.Button()
        self.stop.add(gtk.image_new_from_stock(gtk.STOCK_MEDIA_STOP, SIZE))
        self.stop.connect('clicked', self.__stop_clicked)
        self.pack_start(self.stop, expand=False)

    def __pause_toggled(self, btn):
        if self.task.pausable:
            self.task.paused = btn.props.active

    def __stop_clicked(self, btn):
        if self.task.stoppable:
            self.task.stop()

    def update(self):
        formatted_label = "<b>%s</b>\n%s" % (self.task.source, self.task.desc)
        self.label.set_markup(formatted_label)
        if self.task.frac is not None:
            self.progress.set_fraction(self.task.frac)
        else:
            self.progress.pulse()
        if self.pause.props.sensitive != self.task.pausable:
            self.pause.props.sensitive = self.task.pausable
        show_as_active = (self.task.pausable and self.task.paused)
        if self.pause.props.active != show_as_active:
            self.pause.props.active = show_as_active
        if self.stop.props.sensitive != self.task.stoppable:
            self.stop.props.sensitive = self.task.stoppable

class StatusBar(gtk.HBox):
    def __init__(self, task_controller):
        super(StatusBar, self).__init__()
        self.__dirty = False
        self.set_spacing(12)
        self.task_controller = task_controller
        self.task_controller.parent = self

        self.default_label = gtk.Label()
        self.default_label.set_alignment(1.0, 0.5)
        self.default_label.set_text(_("No time information"))
        self.pack_start(self.default_label)
        self.task_widget = TaskWidget(task_controller)
        self.pack_start(self.task_widget)
        # The history button will eventually hold the full list of running
        # tasks, as well as the list of previous notifications.
        #self.history_btn = gtk.Button(stock=gtk.STOCK_MISSING_IMAGE)
        #self.pack_start(self.history_btn, expand=False)

        self.show_all()
        self.set_no_show_all(True)
        self.__set_shown('default')

    def __set_shown(self, type):
        if type == 'default':   self.default_label.show()
        else:                   self.default_label.hide()
        if type == 'task':      self.task_widget.show()
        else:                   self.task_widget.hide()

    def set_default_text(self, text):
        self.default_label.set_text(text)

    def __update(self):
        self.__dirty = False
        if self.task_controller.active_tasks:
            self.__set_shown('task')
            self.task_widget.update()
        else:
            self.__set_shown('default')

    def update(self):
        if not self.__dirty:
            self.__dirty = True
            gobject.idle_add(self.__update)