Modularize calls to gobject.idle_add (for non-GTK support)

git-svn-id: svn://svn.berlios.de/gpodder/trunk@521 b0d088ad-0a06-0410-aad2-9ed5178a7e87
This commit is contained in:
Thomas Perl 2008-01-15 13:54:22 +00:00
parent 3ea3fabea7
commit 4a25d955e6
10 changed files with 83 additions and 41 deletions

View file

@ -1,3 +1,19 @@
Tue, 15 Jan 2008 14:50:13 +0100 <thp@perli.net>
Modularize calls to gobject.idle_add (for non-GTK support)
* bin/gpodder: Set interface_is_gui to True when running the GUI
* src/gpodder/*.py: Use util.idle_add instead of gobject.idle_add
* src/gpodder/gui.py: Simplify some idle_add calls, code clean-up
* src/gpodder/__init__.py: Add "interface_is_gui" boolean variable
that tells us if we are running in GUI or CLI mode (this is needed for
util.idle_add to determine if it's going to use the gobject module or
not)
* src/gpodder/util.py: Add new function idle_add() that acts as a
wrapper to gobject.idle_add(); this will only use gobject.idle_add if
we are in GUI mode, and will call the callback directly when we are in
command-line mode (because we don't have to watch out for threading
race conditions there, compared to what GTK+ gives us)
Mon, 14 Jan 2008 20:23:02 +0100 <thp@perli.net>
Add menu item that links to gPodder's new bug tracker

View file

@ -119,6 +119,7 @@ def main( argv = sys.argv):
console.del_channel( options.delete)
else:
#default run gui
gpodder.interface_is_gui = True
from gpodder import gui
from gpodder.SimpleGladeApp import bindtextdomain
import gtk.glade

View file

@ -17,5 +17,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# The User-Agent string for downloads
user_agent = 'gPodder'
# Are we running in GUI or console mode?
interface_is_gui = False

View file

@ -25,8 +25,8 @@
import gtk
import gobject
from gpodder import util
from gpodder.liblogger import log
import atexit
@ -170,7 +170,7 @@ class Config(dict):
window.resize( getattr( self, width), getattr( self, height))
window.move( getattr( self, x), getattr( self, y))
self.disable_window_events()
gobject.idle_add(self.enable_window_events)
util.idle_add(self.enable_window_events)
window.connect( 'configure-event', self.receive_configure_event, config_prefix)
else:
raise ValueError( 'Missing settings in set: %s' % ', '.join( ( x, y, width, height )))

View file

@ -93,8 +93,8 @@ class GladeWidget(SimpleGladeApp.SimpleGladeApp):
else:
getattr( self, root).set_position( gtk.WIN_POS_CENTER_ON_PARENT)
def notification( self, message, title = None):
gobject.idle_add( self.show_message, message, title)
def notification(self, message, title=None):
util.idle_add(self.show_message, message, title)
def show_message( self, message, title = None):
dlg = gtk.MessageDialog( GladeWidget.gpodder_main_window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK)
@ -716,8 +716,8 @@ class gPodder(GladeWidget):
sync.close( success = not sync.cancelled)
# update model for played state updates after sync
for channel in self.channels:
gobject.idle_add( channel.update_model)
gobject.idle_add( self.updateComboBox)
util.idle_add(channel.update_model)
util.idle_add(self.updateComboBox)
def ipod_cleanup_callback(self, sync, tracks):
title = _('Delete podcasts on iPod?')
@ -725,7 +725,7 @@ class gPodder(GladeWidget):
if len(tracks) > 0 and self.show_confirmation(message, title):
sync.remove_tracks(tracks)
sync.close(success=not sync.cancelled, cleaned=True)
gobject.idle_add(self.updateTreeView)
util.idle_add(self.updateTreeView)
def ipod_cleanup_proc( self, sync):
if not sync.open():
@ -741,7 +741,7 @@ class gPodder(GladeWidget):
stock_ok_button = gtk.STOCK_DELETE, callback = remove_tracks_callback)
else:
sync.close(success = not sync.cancelled, cleaned = True)
gobject.idle_add(self.updateTreeView)
util.idle_add(self.updateTreeView)
def mp3player_cleanup_proc( self, sync):
if not sync.open():
@ -750,7 +750,7 @@ class gPodder(GladeWidget):
sync.clean_playlist()
sync.close(success = not sync.cancelled, cleaned = True)
gobject.idle_add(self.updateTreeView)
util.idle_add(self.updateTreeView)
def update_feed_cache_callback(self, progressbar, position, count):
title = self.channels[position].title
@ -845,13 +845,12 @@ class gPodder(GladeWidget):
# let's get down to business..
if show_update_dialog:
callback_proc = lambda pos, count: gobject.idle_add(self.update_feed_cache_callback, progressbar, pos, count)
callback_proc = lambda pos, count: util.idle_add(self.update_feed_cache_callback, progressbar, pos, count)
else:
callback_proc = None
callback_error = lambda x: gobject.idle_add( self.show_message, x)
finish_proc = lambda: gobject.idle_add(self.update_feed_cache_finish_callback, force_update, please_wait)
finish_proc = lambda: util.idle_add(self.update_feed_cache_finish_callback, force_update, please_wait)
args = ( force_update, callback_proc, callback_error, finish_proc, )
args = (force_update, callback_proc, self.notification, finish_proc)
thread = Thread( target = self.update_feed_cache_proc, args = args)
thread.start()
@ -1744,7 +1743,7 @@ class gPodderProperties(GladeWidget):
gl = gPodderLib()
gl.downloaddir = self.chooserDownloadTo.get_filename()
if gl.downloaddir != self.chooserDownloadTo.get_filename():
gobject.idle_add( self.show_message, _('There has been an error moving your downloads to the specified location. The old download directory will be used instead.'), _('Error moving downloads'))
self.notification(_('There has been an error moving your downloads to the specified location. The old download directory will be used instead.'), _('Error moving downloads'))
if event:
event.set()
@ -2140,16 +2139,19 @@ class gPodderOpmlLister(GladeWidget):
self.btnOK.set_sensitive( bool(len(self.channels)))
def thread_func( self):
url = self.entryURL.get_text()
importer = opml.Importer( url)
model = importer.get_model()
gobject.idle_add( self.treeviewChannelChooser.set_model, model)
gobject.idle_add( self.labelStatus.set_label, '')
gobject.idle_add( self.btnDownloadOpml.set_sensitive, True)
gobject.idle_add( self.entryURL.set_sensitive, True)
gobject.idle_add( self.treeviewChannelChooser.set_sensitive, True)
def thread_finished(self, model):
self.treeviewChannelChooser.set_model(model)
self.labelStatus.set_label('')
self.btnDownloadOpml.set_sensitive(True)
self.entryURL.set_sensitive(True)
self.treeviewChannelChooser.set_sensitive(True)
self.channels = []
def thread_func(self):
url = self.entryURL.get_text()
importer = opml.Importer(url)
model = importer.get_model()
util.idle_add(self.thread_finished, model)
def get_channels_from_url( self, url, callback_for_channel = None, callback_finished = None):
if callback_for_channel:

View file

@ -25,7 +25,6 @@
import gtk
import gtk.gdk
import gobject
import thread
import threading
import urllib
@ -214,7 +213,7 @@ class gPodderLibClass( object):
def image_download_thread( self, url, callback_pixbuf = None, callback_status = None, callback_finished = None, cover_file = None):
if callback_status != None:
gobject.idle_add( callback_status, _('Downloading channel cover...'))
util.idle_add(callback_status, _('Downloading channel cover...'))
pixbuf = gtk.gdk.PixbufLoader()
if cover_file == None:
@ -247,11 +246,11 @@ class gPodderLibClass( object):
if pb.get_height() > MAX_SIZE:
factor = MAX_SIZE*1.0/pb.get_height()
pb = pb.scale_simple( int(pb.get_width()*factor), int(pb.get_height()*factor), gtk.gdk.INTERP_BILINEAR)
gobject.idle_add( callback_pixbuf, pb)
util.idle_add(callback_pixbuf, pb)
if callback_status != None:
gobject.idle_add( callback_status, '')
util.idle_add(callback_status, '')
if callback_finished != None:
gobject.idle_add( callback_finished)
util.idle_add(callback_finished)
def get_image_from_url( self, url, callback_pixbuf = None, callback_status = None, callback_finished = None, cover_file = None):
if not url and not os.path.exists( cover_file):

View file

@ -78,7 +78,6 @@ import libgpodder
import libconverter
import libtagupdate
import gobject
# do we provide iPod functions to the user?
def ipod_supported():
@ -110,15 +109,15 @@ class gPodderSyncMethod:
def set_progress( self, pos, max):
if self.callback_progress:
gobject.idle_add( self.callback_progress, pos, max)
util.idle_add(self.callback_progress, pos, max)
def set_progress_overall( self, pos, max):
if self.callback_progress:
gobject.idle_add( self.callback_progress, pos, max, True)
util.idle_add(self.callback_progress, pos, max, True)
def set_progress_sub_episode( self, pos, max):
if self.callback_progress:
gobject.idle_add( self.callback_progress, pos, max, False, True)
util.idle_add(self.callback_progress, pos, max, False, True)
def set_episode_status( self, episode):
self.set_status( episode = _('Copying %s') % episode)
@ -132,7 +131,7 @@ class gPodderSyncMethod:
def set_status( self, episode = None, channel = None, progressbar_text = None, title = None, header = None, body = None):
if self.callback_status:
gobject.idle_add( self.callback_status, episode, channel, progressbar_text, title, header, body)
util.idle_add(self.callback_status, episode, channel, progressbar_text, title, header, body)
def sync_channel( self, channel, episodes = None, sync_played_episodes = True):
if not channel.sync_to_devices and episodes == None or self.cancelled:
@ -186,7 +185,7 @@ class gPodderSyncMethod:
pass
if self.callback_done:
gobject.idle_add( self.callback_done, success, access_error, cleaned, self.errors)
util.idle_add(self.callback_done, success, access_error, cleaned, self.errors)
class gPodder_iPodSync( gPodderSyncMethod):

View file

@ -27,6 +27,7 @@
from gpodder.liblogger import log
from gpodder import libgpodder
from gpodder import util
import gtk
import gobject
@ -61,7 +62,7 @@ class ObservableService(object):
def notify(self, signal_name, *args):
if signal_name in self.observers:
for observer in self.observers[signal_name]:
gobject.idle_add(observer, *args)
util.idle_add(observer, *args)
else:
log('Signal "%s" is not available for notification.', signal_name, sender=self)
@ -133,7 +134,7 @@ class DownloadStatusManager(ObservableService):
iter = self.status_list[id]['iter']
if iter != None:
self.tree_model_lock.acquire()
gobject.idle_add( self.remove_iter, iter)
util.idle_add(self.remove_iter, iter)
self.tree_model_lock.release()
self.status_list[id]['iter'] = None
self.status_list[id]['thread'].cancel()
@ -162,7 +163,7 @@ class DownloadStatusManager(ObservableService):
self.tree_model_lock.acquire()
for ( column, key ) in self.COLUMN_NAMES.items():
if key in kwargs:
gobject.idle_add( self.tree_model.set, iter, column, kwargs[key])
util.idle_add(self.tree_model.set, iter, column, kwargs[key])
self.status_list[id][key] = kwargs[key]
self.tree_model_lock.release()
@ -193,7 +194,7 @@ class DownloadStatusManager(ObservableService):
self.status_list[element]['iter'] = None
self.status_list[element]['thread'].cancel()
# clear the tree model after cancelling
gobject.idle_add( self.tree_model.clear)
util.idle_add(self.tree_model.clear)
def cancel_by_url( self, url):
for element in self.status_list:

View file

@ -23,7 +23,6 @@
import gtk
import gobject
from gpodder.liblogger import log
@ -36,6 +35,7 @@ except:
have_pynotify = False
from gpodder import services
from gpodder import util
from libgpodder import gPodderLib
@ -235,7 +235,7 @@ class GPodderStatusIcon(gtk.StatusIcon):
if action=='show':
self.__gpodder.uniconify_main_window()
elif action=='quit':
gobject.idle_add(self.__gpodder.close_gpodder)
util.idle_add(self.__gpodder.close_gpodder)
elif action=='ignore':
pass
elif action=='keep_dowloading':

View file

@ -29,10 +29,11 @@ are not tied to any specific part of gPodder.
"""
import gpodder
from gpodder.liblogger import log
import gtk
import gobject
import os
import os.path
@ -585,3 +586,22 @@ def itunes_discover_rss(url):
return None
def idle_add(func, *args):
"""
This is a wrapper function that does the Right
Thing depending on if we are running a GTK+ GUI or
not. If not, we're simply calling the function.
If we are a GUI app, we use gobject.idle_add() to
call the function later - this is needed for
threads to be able to modify GTK+ widget data.
"""
if gpodder.interface_is_gui:
def x(f, *a):
f(*a)
return False
gobject.idle_add(func, *args)
else:
func(*args)