home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / rhythmbox / plugins / artdisplay / __init__.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  18.7 KB  |  499 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. import rhythmdb
  5. import rb
  6. import gtk
  7. import gobject
  8. from warnings import warn
  9. from CoverArtDatabase import CoverArtDatabase
  10. FADE_STEPS = 10
  11. FADE_TOTAL_TIME = 1000
  12. ART_MISSING_ICON = 'rhythmbox-missing-artwork'
  13. WORKING_DELAY = 500
  14. THROBBER_RATE = 10
  15. THROBBER = 'gnome-spinner'
  16. ASPECT_RATIO_MIN = 0.9
  17. ASPECT_RATIO_MAX = 1.1
  18.  
  19. def merge_pixbufs(old_pb, new_pb, reserve_pb, step, width, height, mode = gtk.gdk.INTERP_BILINEAR):
  20.     if width <= 1 and height <= 1:
  21.         return None
  22.     if old_pb is None:
  23.         if new_pb is None:
  24.             return reserve_pb
  25.         return new_pb.scale_simple(width, height, mode)
  26.     old_pb is None
  27.     if step == 0:
  28.         return old_pb.scale_simple(width, height, mode)
  29.     sw = float(width) / new_pb.props.width
  30.     sh = float(height) / new_pb.props.height
  31.     alpha = int(step * 255)
  32.     ret = old_pb.scale_simple(width, height, mode)
  33.     new_pb.composite(ret, 0, 0, width, height, 0, 0, sw, sh, mode, alpha)
  34.     return ret
  35.  
  36.  
  37. def merge_with_background(pixbuf, bgcolor, pad_if_not_near_square):
  38.     if pixbuf is None:
  39.         return pixbuf
  40.     has_alpha = pixbuf.get_has_alpha()
  41.     width = pixbuf.props.width
  42.     height = pixbuf.props.height
  43.     if pad_if_not_near_square:
  44.         if height < width * ASPECT_RATIO_MIN or height > width * ASPECT_RATIO_MAX:
  45.             rw = max(width, height)
  46.             rh = max(width, height)
  47.             left = (rw - width) // 2
  48.             top = (rh - height) // 2
  49.         elif not has_alpha:
  50.             return pixbuf
  51.     (rw, rh, left, top) = (width, height, 0, 0)
  52.     ret = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, rw, rh)
  53.     ret.fill((bgcolor.red & 65280) << 16 | (bgcolor.green & 65280) << 8 | bgcolor.blue & 65280 | 255)
  54.     if has_alpha:
  55.         pixbuf.composite(ret, left, top, width, height, left, top, 1, 1, gtk.gdk.INTERP_NEAREST, 255)
  56.     else:
  57.         pixbuf.copy_area(0, 0, width, height, ret, left, top)
  58.     return ret
  59.  
  60.  
  61. class FadingImage(gtk.Misc):
  62.     __gsignals__ = {
  63.         'size-allocate': 'override' }
  64.     
  65.     def __init__(self, missing_image):
  66.         gobject.GObject.__init__(self)
  67.         self.sc_id = self.connect('screen-changed', self.screen_changed)
  68.         self.ex_id = self.connect('expose-event', self.expose)
  69.         self.sr_id = self.connect('size-request', self.size_request)
  70.         (self.resize_id, self.fade_id, self.anim_id) = (0, 0, 0)
  71.         self.missing_image = missing_image
  72.         self.size = 100
  73.         self.screen_changed(self, None)
  74.         (self.old_pixbuf, self.new_pixbuf) = (None, None)
  75.         (self.merged_pixbuf, self.missing_pixbuf) = (None, None)
  76.         self.fade_step = 0
  77.         (self.anim, self.anim_frames, self.anim_size) = (None, None, 0)
  78.  
  79.     
  80.     def disconnect_handlers(self):
  81.         for id in (self.sc_id, self.ex_id, self.sr_id):
  82.             self.disconnect(id)
  83.         
  84.         self.icon_theme.disconnect(self.tc_id)
  85.         for id in (self.resize_id, self.fade_id, self.anim_id):
  86.             if id != 0:
  87.                 gobject.source_remove(id)
  88.                 continue
  89.         
  90.  
  91.     
  92.     def screen_changed(self, widget, old_screen):
  93.         if old_screen:
  94.             self.icon_theme.disconnect(self.tc_id)
  95.         
  96.         self.icon_theme = gtk.icon_theme_get_for_screen(self.get_screen())
  97.         self.tc_id = self.icon_theme.connect('changed', self.theme_changed)
  98.         self.theme_changed(self.icon_theme)
  99.  
  100.     
  101.     def reload_anim_frames(self):
  102.         icon_info = self.icon_theme.lookup_icon(THROBBER, -1, 0)
  103.         size = icon_info.get_base_size()
  104.         icon = gtk.gdk.pixbuf_new_from_file(icon_info.get_filename())
  105.         self.anim_frames = [ icon.subpixbuf(x * size, y * size, size, size) for y in range(int(icon.props.height / size)) for x in range(int(icon.props.width / size)) ]
  106.         self.anim_size = size
  107.  
  108.     
  109.     def theme_changed(self, icon_theme):
  110.         
  111.         try:
  112.             self.reload_anim_frames()
  113.         except Exception:
  114.             e = None
  115.             warn('Throbber animation not loaded: %s' % e, Warning)
  116.  
  117.         self.reload_util_pixbufs()
  118.  
  119.     
  120.     def reload_util_pixbufs(self):
  121.         if self.size <= 1:
  122.             return None
  123.         
  124.         try:
  125.             missing_pixbuf = self.icon_theme.load_icon(ART_MISSING_ICON, self.size, 0)
  126.         except:
  127.             self.size <= 1
  128.             
  129.             try:
  130.                 missing_pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.missing_image, self.size, self.size)
  131.             except Exception:
  132.                 e = None
  133.                 warn('Missing artwork icon not found: %s' % e, Warning)
  134.                 return None
  135.             
  136.  
  137.  
  138.         self.missing_pixbuf = merge_with_background(missing_pixbuf, self.style.bg[gtk.STATE_NORMAL], False)
  139.  
  140.     
  141.     def do_size_allocate(self, allocation):
  142.         self.allocation = allocation
  143.         if self.resize_id == 0:
  144.             self.resize_id = gobject.idle_add(self.after_resize)
  145.         
  146.         if self.size != allocation.width:
  147.             self.size = allocation.width
  148.             self.queue_resize()
  149.         elif self.window is not None:
  150.             self.window.move_resize(allocation.x, allocation.y, allocation.width, allocation.height)
  151.             self.queue_draw()
  152.             self.window.process_updates(True)
  153.         
  154.  
  155.     
  156.     def after_resize(self):
  157.         self.reload_util_pixbufs()
  158.         self.merged_pixbuf = None
  159.         self.queue_draw()
  160.         return False
  161.  
  162.     
  163.     def size_request(self, widget, requisition):
  164.         requisition.width = -1
  165.         requisition.height = self.size
  166.  
  167.     
  168.     def expose(self, widget, event):
  169.         if not self.ensure_merged_pixbuf():
  170.             return False
  171.         if self.merged_pixbuf.props.width != self.size:
  172.             draw_pb = self.merged_pixbuf.scale_simple(self.size, self.size, gtk.gdk.INTERP_NEAREST)
  173.         else:
  174.             draw_pb = self.merged_pixbuf
  175.         (x, y, w, h) = event.area
  176.         event.window.draw_pixbuf(None, draw_pb, x, y, x, y, min(w, self.size - x), min(h, self.size - y))
  177.         if self.anim:
  178.             (x, y, w, h) = self.anim_rect()
  179.             event.window.draw_pixbuf(None, self.anim, max(0, -x), max(0, -y), max(0, x), max(0, y), w, h)
  180.         
  181.         return False
  182.  
  183.     
  184.     def anim_rect(self):
  185.         return gtk.gdk.Rectangle((self.allocation.width - self.anim_size) / 2, (self.allocation.height - self.anim_size) / 2, min(self.anim_size, self.allocation.width), min(self.anim_size, self.allocation.height))
  186.  
  187.     
  188.     def ensure_merged_pixbuf(self):
  189.         if self.merged_pixbuf is None:
  190.             self.merged_pixbuf = merge_pixbufs(self.old_pixbuf, self.new_pixbuf, self.missing_pixbuf, self.fade_step, self.allocation.width, self.allocation.height)
  191.         
  192.         return self.merged_pixbuf
  193.  
  194.     
  195.     def render_overlay(self):
  196.         ret = self.ensure_merged_pixbuf()
  197.         if ret and self.anim:
  198.             if ret is self.missing_pixbuf:
  199.                 ret = ret.copy()
  200.             
  201.             (x, y, w, h) = self.anim_rect()
  202.             self.anim.composite(ret, max(x, 0), max(y, 0), w, h, x, y, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
  203.         
  204.         return ret
  205.  
  206.     
  207.     def fade_art(self, first_time):
  208.         self.fade_step += 1 / FADE_STEPS
  209.         if self.fade_step > 0.999:
  210.             self.old_pixbuf = None
  211.             self.fade_id = 0
  212.         
  213.         self.merged_pixbuf = None
  214.         if first_time:
  215.             self.fade_id = gobject.timeout_add(FADE_TOTAL_TIME / FADE_STEPS, self.fade_art, False)
  216.             return False
  217.         self.queue_resize()
  218.         return self.fade_step <= 0.999
  219.  
  220.     
  221.     def animation_advance(self, counter, first_time):
  222.         self.anim = self.anim_frames[counter[0]]
  223.         counter[0] = (counter[0] + 1) % len(self.anim_frames)
  224.         (x, y, w, h) = self.anim_rect()
  225.         self.queue_draw_area(max(x, 0), max(y, 0), w, h)
  226.         if first_time:
  227.             self.anim_id = gobject.timeout_add(int(1000 / THROBBER_RATE), self.animation_advance, counter, False)
  228.             return False
  229.         return True
  230.  
  231.     
  232.     def set_current_art(self, pixbuf, working):
  233.         if self.props.visible and self.parent.allocation.width > 1:
  234.             self.old_pixbuf = self.render_overlay()
  235.         else:
  236.             self.old_pixbuf = None
  237.         self.new_pixbuf = merge_with_background(pixbuf, self.style.bg[gtk.STATE_NORMAL], True)
  238.         self.merged_pixbuf = None
  239.         self.fade_step = 0
  240.         self.anim = None
  241.         if self.fade_id != 0:
  242.             gobject.source_remove(self.fade_id)
  243.             self.fade_id = 0
  244.         
  245.         if self.old_pixbuf is not None:
  246.             if not working or WORKING_DELAY:
  247.                 pass
  248.             self.fade_id = gobject.timeout_add(FADE_TOTAL_TIME / FADE_STEPS, self.fade_art, working)
  249.         
  250.         if working and self.anim_id == 0 and self.anim_frames:
  251.             self.anim_id = gobject.timeout_add(WORKING_DELAY, self.animation_advance, [
  252.                 0], True)
  253.         
  254.         if not working and self.anim_id != 0:
  255.             gobject.source_remove(self.anim_id)
  256.             self.anim_id = 0
  257.         
  258.         self.queue_resize()
  259.  
  260.  
  261. gobject.type_register(FadingImage)
  262.  
  263. class ArtDisplayWidget(FadingImage):
  264.     __gsignals__ = {
  265.         'pixbuf-dropped': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (rhythmdb.Entry, gtk.gdk.Pixbuf)),
  266.         'uri-dropped': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (rhythmdb.Entry, gobject.TYPE_STRING)) }
  267.     
  268.     def __init__(self, missing_image):
  269.         super(ArtDisplayWidget, self).__init__(missing_image)
  270.         self.set_padding(0, 5)
  271.         self.ddg_id = self.connect('drag-data-get', self.drag_data_get)
  272.         self.ddr_id = self.connect('drag-data-received', self.drag_data_received)
  273.         self.current_entry = None
  274.         self.working = False
  275.         (self.current_pixbuf, self.current_uri) = (None, None)
  276.  
  277.     
  278.     def disconnect_handlers(self):
  279.         super(ArtDisplayWidget, self).disconnect_handlers()
  280.         self.disconnect(self.ddg_id)
  281.         self.disconnect(self.ddr_id)
  282.  
  283.     
  284.     def update_dnd_targets(self):
  285.         targets = None
  286.         if self.current_entry:
  287.             targets = gtk.target_list_add_image_targets(targets)
  288.             targets = gtk.target_list_add_uri_targets(targets)
  289.             targets = gtk.target_list_add_text_targets(targets)
  290.         
  291.         if targets:
  292.             self.drag_dest_set(gtk.DEST_DEFAULT_ALL, targets, gtk.gdk.ACTION_COPY)
  293.         else:
  294.             self.drag_dest_unset()
  295.         targets = None
  296.         if self.current_pixbuf:
  297.             targets = gtk.target_list_add_image_targets(targets, writable = True)
  298.         
  299.         if self.current_uri:
  300.             targets = gtk.target_list_add_uri_targets(targets)
  301.         
  302.         if targets:
  303.             self.drag_source_set(gtk.gdk.BUTTON1_MASK, targets, gtk.gdk.ACTION_COPY)
  304.         else:
  305.             self.drag_source_unset()
  306.  
  307.     
  308.     def update_tooltips(self, working):
  309.         if not self.current_entry:
  310.             self.set_tooltip_text(None)
  311.         elif working:
  312.             self.set_tooltip_text(_('Searching... drop artwork here'))
  313.         else:
  314.             self.set_tooltip_text(_('Drop artwork here'))
  315.  
  316.     
  317.     def set(self, entry, pixbuf, uri, working):
  318.         self.current_entry = entry
  319.         self.current_pixbuf = pixbuf
  320.         self.current_uri = uri
  321.         self.set_current_art(pixbuf, working)
  322.         self.update_dnd_targets()
  323.         self.update_tooltips(working)
  324.  
  325.     
  326.     def drag_data_get(self, widget, drag_context, selection_data, info, timestamp):
  327.         if self.current_pixbuf:
  328.             selection_data.set_pixbuf(self.current_pixbuf)
  329.         
  330.         if self.current_uri:
  331.             selection_data.set_uris([
  332.                 self.current_uri])
  333.         
  334.  
  335.     
  336.     def drag_data_received(self, widget, drag_context, x, y, selection_data, info, timestamp):
  337.         entry = self.current_entry
  338.         pixbuf = selection_data.get_pixbuf()
  339.         uris = selection_data.get_uris()
  340.         text = selection_data.get_text()
  341.         if pixbuf:
  342.             self.emit('pixbuf-dropped', entry, pixbuf)
  343.         elif uris:
  344.             self.emit('uri-dropped', entry, uris[0])
  345.         elif text:
  346.             self.emit('uri-dropped', entry, text)
  347.         
  348.  
  349.  
  350. gobject.type_register(ArtDisplayWidget)
  351.  
  352. class ArtDisplayPlugin(rb.Plugin):
  353.     
  354.     def __init__(self):
  355.         rb.Plugin.__init__(self)
  356.  
  357.     
  358.     def activate(self, shell):
  359.         self.shell = shell
  360.         sp = shell.get_player()
  361.         self.player_cb_ids = (sp.connect('playing-song-changed', self.playing_entry_changed), sp.connect('playing-changed', self.playing_changed))
  362.         db = shell.get_property('db')
  363.         self.db_cb_ids = (db.connect_after('entry-extra-metadata-request::rb:coverArt', self.cover_art_request), db.connect_after('entry-extra-metadata-notify::rb:coverArt', self.cover_art_notify), db.connect_after('entry-extra-metadata-request::rb:coverArt-uri', self.cover_art_uri_request), db.connect_after('entry-extra-metadata-notify::rb:coverArt-uri', self.cover_art_uri_notify), db.connect_after('entry-extra-metadata-gather', self.cover_art_uri_gather))
  364.         self.art_widget = ArtDisplayWidget(self.find_file(ART_MISSING_ICON + '.svg'))
  365.         self.art_widget.connect('pixbuf-dropped', self.on_set_pixbuf)
  366.         self.art_widget.connect('uri-dropped', self.on_set_uri)
  367.         self.art_container = gtk.VBox()
  368.         self.art_container.pack_start(self.art_widget, padding = 6)
  369.         shell.add_widget(self.art_container, rb.SHELL_UI_LOCATION_SIDEBAR)
  370.         self.art_db = CoverArtDatabase()
  371.         (self.current_entry, self.current_pixbuf) = (None, None)
  372.         self.playing_entry_changed(sp, sp.get_playing_entry())
  373.  
  374.     
  375.     def deactivate(self, shell):
  376.         self.shell = None
  377.         sp = shell.get_player()
  378.         for id in self.player_cb_ids:
  379.             sp.disconnect(id)
  380.         
  381.         self.player_cb_ids = ()
  382.         db = shell.get_property('db')
  383.         for id in self.db_cb_ids:
  384.             db.disconnect(id)
  385.         
  386.         self.db_cb_ids = ()
  387.         shell.remove_widget(self.art_container, rb.SHELL_UI_LOCATION_SIDEBAR)
  388.         self.art_widget.disconnect_handlers()
  389.         self.art_widget = None
  390.         self.art_db = None
  391.  
  392.     
  393.     def playing_changed(self, sp, playing):
  394.         self.set_entry(sp.get_playing_entry())
  395.  
  396.     
  397.     def playing_entry_changed(self, sp, entry):
  398.         self.set_entry(entry)
  399.  
  400.     
  401.     def set_entry(self, entry):
  402.         if entry == self.current_entry:
  403.             return None
  404.         db = self.shell.get_property('db')
  405.         self.art_widget.set(entry, None, None, True)
  406.         self.art_container.show_all()
  407.         self.current_entry = entry
  408.         self.current_pixbuf = None
  409.         self.art_db.get_pixbuf(db, entry, self.on_get_pixbuf_completed)
  410.  
  411.     
  412.     def on_get_pixbuf_completed(self, entry, pixbuf, uri):
  413.         if entry != self.current_entry:
  414.             return None
  415.         self.current_pixbuf = pixbuf
  416.         self.art_widget.set(entry, pixbuf, uri, False)
  417.         if pixbuf:
  418.             db = self.shell.get_property('db')
  419.             
  420.             def idle_emit_art():
  421.                 db.emit_entry_extra_metadata_notify(entry, 'rb:coverArt', pixbuf)
  422.                 return False
  423.  
  424.             gobject.idle_add(idle_emit_art)
  425.         
  426.  
  427.     
  428.     def cover_art_request(self, db, entry):
  429.         if entry == self.current_entry:
  430.             return self.current_pixbuf
  431.  
  432.     
  433.     def cover_art_notify(self, db, entry, field, metadata):
  434.         if entry != self.current_entry:
  435.             return None
  436.         if not isinstance(metadata, gtk.gdk.Pixbuf):
  437.             return None
  438.         self.art_db.cancel_get_pixbuf(entry)
  439.         if self.current_pixbuf == metadata:
  440.             return None
  441.         self.art_widget.set(entry, metadata, None, False)
  442.  
  443.     
  444.     def cover_art_uri_notify(self, db, entry, field, metadata):
  445.         if entry != self.current_entry:
  446.             return None
  447.         if not metadata:
  448.             print 'got no-cover-art notification'
  449.             self.art_widget.set(entry, None, None, False)
  450.             db.emit_entry_extra_metadata_notify(entry, 'rb:coverArt', None)
  451.             return None
  452.         uri = str(metadata)
  453.         
  454.         def loader_cb(data):
  455.             if data and len(data) >= 1000:
  456.                 pbl = gtk.gdk.PixbufLoader()
  457.                 
  458.                 try:
  459.                     if pbl.write(data) and pbl.close():
  460.                         pixbuf = pbl.get_pixbuf()
  461.                         if pixbuf:
  462.                             self.art_db.cancel_get_pixbuf(entry)
  463.                             self.on_get_pixbuf_completed(entry, pixbuf, uri)
  464.                         
  465.                 except GError:
  466.                     pass
  467.                 except:
  468.                     None<EXCEPTION MATCH>GError
  469.                 
  470.  
  471.             None<EXCEPTION MATCH>GError
  472.  
  473.         print 'got cover art URI notification: %s' % uri
  474.         l = rb.Loader()
  475.         l.get_url(uri, loader_cb)
  476.  
  477.     
  478.     def cover_art_uri_request(self, db, entry):
  479.         if entry == self.current_entry:
  480.             return self.art_widget.current_uri
  481.  
  482.     
  483.     def cover_art_uri_gather(self, db, entry, metadata):
  484.         if entry == self.current_entry and self.art_widget.current_uri:
  485.             metadata['rb:coverArt-uri'] = self.art_widget.current_uri
  486.         
  487.  
  488.     
  489.     def on_set_pixbuf(self, widget, entry, pixbuf):
  490.         db = self.shell.get_property('db')
  491.         self.art_db.set_pixbuf(db, entry, pixbuf, self.on_get_pixbuf_completed)
  492.  
  493.     
  494.     def on_set_uri(self, widget, entry, uri):
  495.         db = self.shell.get_property('db')
  496.         self.art_db.set_pixbuf_from_uri(db, entry, uri, self.on_get_pixbuf_completed)
  497.  
  498.  
  499.