def __zerolistener(self, *args): if self.ended: return False cur_time = time() whites_time = cur_time + self.getPlayerTime(WHITE) blacks_time = cur_time + self.getPlayerTime(BLACK) if whites_time <= blacks_time: the_time = whites_time color = WHITE else: the_time = blacks_time color = BLACK remaining_time = the_time - cur_time + 0.01 if remaining_time > 0 and remaining_time != self.zero_listener_time: if (self.zero_listener_id is not None) and \ (self.zero_listener_source is not None) and \ not self.zero_listener_source.is_destroyed(): GLib.source_remove(self.zero_listener_id) self.zero_listener_time = remaining_time self.zero_listener_id = GLib.timeout_add(10, self.__checkzero, color) default_context = GLib.main_context_get_thread_default( ) or GLib.main_context_default() if hasattr(default_context, "find_source_by_id"): self.zero_listener_source = default_context.find_source_by_id( self.zero_listener_id)
def _sync(self, playlists, convert): """ Sync playlists with device as this @param playlists as [str] @param convert as bool """ try: self._in_thread = True self._convert = convert self._errors = False self._errors_count = 0 self._copied_art_uris = [] # For progress bar self._total = 1 self._done = 0 self._fraction = 0.0 plnames = [] # New tracks for playlist in playlists: plnames.append(Lp().playlists.get_name(playlist)) self._fraction = self._done/self._total self._total += len(Lp().playlists.get_tracks(playlist)) # Old tracks try: children = self._get_tracks_files() self._total += len(children) except: pass GLib.idle_add(self._update_progress) # Copy new tracks to device if self._syncing: self._copy_to_device(playlists) # Remove old tracks from device if self._syncing: self._remove_from_device(playlists) # Delete old playlists d = Gio.File.new_for_uri(self._uri) infos = d.enumerate_children( 'standard::name', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, None) for info in infos: f = info.get_name() if f.endswith(".m3u") and f[:-4] not in plnames: uri = self._uri+'/'+f d = Gio.File.new_for_uri(uri) self._retry(d.delete, (None,)) except Exception as e: print("DeviceManagerWidget::_sync(): %s" % e) self._fraction = 1.0 self._syncing = False self._in_thread = False if self._errors: GLib.idle_add(self._on_errors)
def _recalc_width(self, path, text): self._texts[path[0]] = text if self._timeout is not None: GLib.source_remove(self._timeout) self._timeout = None self._timeout = GLib.idle_add(self._delayed_recalc, priority=GLib.PRIORITY_LOW)
def capture_glib_warnings(allow_warnings=False, allow_criticals=False): """Temporarily suppress glib warning output and record them. The test suite is run with G_DEBUG="fatal-warnings fatal-criticals" by default. Setting allow_warnings and allow_criticals will temporarily allow warnings or criticals without terminating the test run. """ old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags(0)) new_mask = old_mask if allow_warnings: new_mask &= ~GLib.LogLevelFlags.LEVEL_WARNING if allow_criticals: new_mask &= ~GLib.LogLevelFlags.LEVEL_CRITICAL GLib.log_set_always_fatal(GLib.LogLevelFlags(new_mask)) GLibWarning = gi._gi._gobject.Warning try: with warnings.catch_warnings(record=True) as warn: warnings.filterwarnings('always', category=GLibWarning) yield warn finally: GLib.log_set_always_fatal(old_mask)
def populate(self): """ Populate view """ if Lp.player.get_queue(): self._clear_btn.set_sensitive(True) GLib.idle_add(self._add_items, list(Lp.player.get_queue()))
def close(self, *a): """ Closes revealer (with animation), removes it from parent and calls destroy() """ self.set_reveal_child(False) GLib.timeout_add(self.get_transition_duration() + 50, self._cb_destroy)
def _set_transaction(self, transaction): """Connect the dialog to the given aptdaemon transaction""" for sig in self._signals: GLib.source_remove(sig) self._signals = [] self.current_trans = transaction self._signals.append(transaction.connect_after("status-changed", self._on_status_changed)) self._signals.append(transaction.connect("status-details-changed", self._on_status_details_changed)) self._signals.append(transaction.connect("role-changed", self._on_role_changed)) self._signals.append(transaction.connect("medium-required", self._on_medium_required)) self._signals.append(transaction.connect("config-file-conflict", self._on_config_file_conflict)) self._signals.append(transaction.connect("progress-changed", self._on_progress_changed)) self._signals.append(transaction.connect("progress-details-changed", self._on_progress_details_changed)) self._signals.append(transaction.connect("cancellable-changed", self._on_cancellable_changed)) self._signals.append(transaction.connect("progress-download-changed", self._on_download_changed)) self._signals.append(transaction.connect("terminal-attached-changed", self._on_terminal_attached_changed)) self._on_role_changed(transaction, transaction.role) if self._ttyname: transaction.set_terminal(self._ttyname)
def _switch_to_player_view(self): self.settings.set_boolean('did-initial-state', True) self._on_notify_model_id = self._stack.connect('notify::visible-child', self._on_notify_mode) self.connect('destroy', self._notify_mode_disconnect) self._key_press_event_id = self.connect('key_press_event', self._on_key_press) self.views.append(AlbumsView(self, self.player)) self.views.append(ArtistsView(self, self.player)) self.views.append(SongsView(self, self.player)) self.views.append(PlaylistView(self, self.player)) self.views.append(SearchView(self, self.player)) self.views.append(EmptySearchView(self, self.player)) for i in self.views: if i.title: self._stack.add_titled(i, i.name, i.title) else: self._stack.add_named(i, i.name) self.toolbar.set_stack(self._stack) self.toolbar.searchbar.show() self.toolbar.dropdown.show() for i in self.views: GLib.idle_add(i.populate)
def show_playlist_notification(self): """Show a notification on playlist removal and provide an option to undo for 5 seconds. """ # Callback to remove playlists def remove_playlist_timeout_cb(self): # Remove the playlist self.views[3].really_delete = False playlist.delete_playlist(self.views[3].pl_todelete) # Hide the notification self._playlist_notification.set_reveal_child(False) # Stop the timeout self._playlist_notification_timeout_id = 0 return GLib.SOURCE_REMOVE # If a notification is already visible, remove that playlist if self._playlist_notification_timeout_id > 0: GLib.source_remove(self._playlist_notification_timeout_id) remove_playlist_timeout_cb(self) playlist_title = self.views[3].current_playlist.get_title() label = _("Playlist {} removed".format(playlist_title)) self._playlist_notification.label.set_label(label) self._playlist_notification.set_reveal_child(True) timeout_id = GLib.timeout_add_seconds(5, remove_playlist_timeout_cb, self) self._playlist_notification_timeout_id = timeout_id
def _syncthing_cb_config_error(self, exception, command): self.cancel_all() if isinstance(exception, GLib.GError): if exception.code in (0, 39, 34, 45): # Connection Refused / Cannot connect to destination # It usualy means that daemon is not yet fully started or not running at all. epoch = self._epoch self.emit("connection-error", Daemon.REFUSED, exception.message, exception) if epoch == self._epoch: self.timer("config", self._refresh_interval, self._rest_request, "system/config", self._syncthing_cb_config, self._syncthing_cb_config_error) return elif isinstance(exception, HTTPAuthException): self.emit("connection-error", Daemon.NOT_AUTHORIZED, exception.message, exception) return elif isinstance(exception, HTTPCode): # HTTP 404 may acually mean old daemon version version = get_header(exception.headers, "X-Syncthing-Version") if version != None and not compare_version(version, MIN_VERSION): self._epoch += 1 msg = "daemon is too old" self.emit("connection-error", Daemon.OLD_VERSION, msg, Exception(msg)) else: self.emit("connection-error", Daemon.UNKNOWN, exception.message, exception) return elif isinstance(exception, TLSUnsupportedException): self.emit("connection-error", Daemon.TLS_UNSUPPORTED, exception.message, exception) return elif isinstance(exception, ConnectionRestarted): # Happens on Windows. Just try again. GLib.idle_add(self._request_config) return elif isinstance(exception, TLSUnsupportedException): self.emit("connection-error", Daemon.TLS_UNSUPPORTED, exception.message, exception) return self.emit("connection-error", Daemon.UNKNOWN, exception.message, exception)
def reconnect(self): """ Cancel all pending requests, throw away all data and (re)connect. Should be called from glib loop """ self.close() GLib.idle_add(self._request_config)
def main(): # These imports were moved here because the keysign module # can be imported without wanting to run it, e.g. setup.py # imports the __version__ import logging, sys, signal import gi gi.require_version('Gtk', '3.0') from gi.repository import GLib, Gtk from .MainWindow import MainWindow logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, format='%(name)s (%(levelname)s): %(message)s') app = MainWindow() try: GLib.unix_signal_add_full(GLib.PRIORITY_HIGH, signal.SIGINT, lambda *args : app.quit(), None) except AttributeError: pass exit_status = app.run(None) return exit_status
def tree_append_items(tree, items): '''A faster way to append many items to GtkTreeModel at a time. When appending many items to a model , app will lose response, which is really annoying. From:http://faq.pygtk.org/index.py?req=show&file=faq13.043.htp @tree a GtkTreeView @items a list of items ''' def append_generator(step=100): n = 0 tree.freeze_child_notify() for item in items: model.append(item) n += 1 if (n % step) == 0: tree.thaw_child_notify() yield True tree.freeze_child_notify() # stop idle_add() tree.thaw_child_notify() yield False model = tree.get_model() loader = append_generator() GLib.idle_add(loader.__next__)
def do_show(self): """ Init signals, set color and go party mode if nothing is playing """ self._signal1_id = Lp().player.connect('current-changed', self.on_current_changed) self._signal2_id = Lp().player.connect('status-changed', self.on_status_changed) if Lp().player.current_track.id is None: Lp().player.set_party(True) else: self.on_status_changed(Lp().player) self.on_current_changed(Lp().player) if self._timeout1 is None: self._timeout1 = GLib.timeout_add(1000, self._update_position) Gtk.Window.do_show(self) now = datetime.now() self._datetime.set_label(now.strftime('%a %d %b, %X')[:-3]) if self._timeout2 is None: second = datetime.now().second if 60 - second > 0: GLib.timeout_add((60-second)*1000, self._update_datetime) else: self._timeout2 = GLib.timeout_add(60000, self._update_datetime) self._update_position() self.fullscreen() self._next_popover.set_relative_to(self._album_label) if Lp().player.next_track.id != Type.RADIOS: self._next_popover.show()
def run_dbus_service(self, timeout=None, send_usr1=False): '''Run D-BUS server. If no timeout is given, the server will run forever, otherwise it will return after the specified number of seconds. If send_usr1 is True, this will send a SIGUSR1 to the parent process once the server is ready to take requests. ''' dbus.service.Object.__init__(self, self.bus, '/DeviceDriver') self.main_loop = GLib.MainLoop() self._timeout = False if timeout: def _t(): self.main_loop.quit() return True GLib.timeout_add(timeout * 1000, _t) # send parent process a signal that we are ready now if send_usr1: os.kill(os.getppid(), signal.SIGUSR1) # run until we time out while not self._timeout: if timeout: self._timeout = True self.main_loop.run()
def _configure_cb(self, widget, event): """Internal: Update size and prefs when window is adjusted""" # Constrain window to fit on its current monitor, if possible. screen = event.get_screen() mon = screen.get_monitor_at_point(event.x, event.y) mon_geom = screen.get_monitor_geometry(mon) # Constrain width and height w = clamp(int(event.width), self.MIN_WIDTH, self.MAX_WIDTH) h = clamp(int(event.height), self.MIN_HEIGHT, self.MAX_HEIGHT) # Constrain position x, y = event.x, event.y if y+h > mon_geom.y + mon_geom.height: y = mon_geom.y + mon_geom.height - h if x+w > mon_geom.x + mon_geom.width: x = mon_geom.x + mon_geom.width - w if x < mon_geom.x: x = mon_geom.x if y < mon_geom.y: y = mon_geom.y event_size = (event.x, event.y, event.width, event.height) ex, ey, ew, eh = [int(c) for c in event_size] x, y, w, h = [int(c) for c in (x, y, w, h)] if not self._corrected_pos: if (x, y) != (ex, ey): GLib.idle_add(self.move, x, y) if (w, h) != (ew, eh): GLib.idle_add(self.resize, w, h) self._corrected_pos = True # Record size self._size = (x, y, w, h) self.app.preferences[self._prefs_size_key] = (w, h)
def __init__(self): Gtk.Window.__init__(self) self.image = None GLib.timeout_add(50, self.save_image) self.connect("delete-event", self.on_quit) # Status self.status = Gst.State.NULL # Video Area self.video_area = Gtk.DrawingArea() # Disable Double Buffered self.video_area.set_double_buffered(False) # playbin self.player = Gst.parse_launch("tcpclientsrc host=" + sys.argv[1] +" port=5000 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! xvimagesink name=xv") bus = self.player.get_bus() bus.add_signal_watch() bus.enable_sync_message_emission() bus.connect("message", self.on_message) bus.connect("sync-message::element", self.on_sync_message) # DnD dnd_list = Gtk.TargetEntry.new("text/uri-list", 0, 0) # pack vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) vbox.pack_start(self.video_area, True, True, 0) self.add(vbox) self.resize(640, 480) self.show_all() self.player.set_state(Gst.State.PLAYING)
def _updatePositionCb(self, pipeline, position): """ Unlike other progression indicator callbacks, this one occurs every time the pipeline emits a position changed signal, which is *very* often. This should only be used for a smooth progressbar/percentage, not text. """ self.current_position = position if not self.progress or not position: return length = self.app.current_project.timeline.props.duration fraction = float(min(position, length)) / float(length) self.progress.updatePosition(fraction) # In order to have enough averaging, only display the ETA after 5s timediff = time.time() - self._time_started if not self._timeEstimateTimer: if timediff < 6: self.progress.progressbar.set_text(_("Estimating...")) else: self._timeEstimateTimer = GLib.timeout_add_seconds(3, self._updateTimeEstimateCb) # Filesize is trickier and needs more time to be meaningful: if not self._filesizeEstimateTimer and (fraction > 0.33 or timediff > 180): self._filesizeEstimateTimer = GLib.timeout_add_seconds(5, self._updateFilesizeEstimateCb)
def on_motor_position_change(self, motor: Optional[Motor], pos: Optional[float]): if motor is None or pos is None: logger.debug('Faked motor position changed signal caught by ShutterFrame.') else: logger.debug( 'Motor position changed signal caught by ShutterFrame. Motor: {}. Position: {}'.format(motor.name, pos)) try: logger.debug('Stored motor position is {}'.format(motor.where())) except KeyError: logger.debug('Stored motor position not yet available.') try: if motor is not None: beamstopstate = self.instrument.get_beamstop_state(**{motor.name: pos}) else: beamstopstate = self.instrument.get_beamstop_state() logger.debug('beamstopstate: {}'.format(beamstopstate)) except KeyError: # can happen at program initialization, when the motor position has not yet been read. logger.debug('No beamstop state yet.') GLib.timeout_add(1000, lambda m=motor, p=pos: self.on_motor_position_change(m, p)) return False if beamstopstate == 'in': self.builder.get_object('beamstopstate_image').set_from_icon_name('beamstop-in', Gtk.IconSize.BUTTON) self.builder.get_object('beamstop_in_button').set_sensitive(False) self.builder.get_object('beamstop_out_button').set_sensitive(True) elif beamstopstate == 'out': self.builder.get_object('beamstopstate_image').set_from_icon_name('beamstop-out', Gtk.IconSize.BUTTON) self.builder.get_object('beamstop_in_button').set_sensitive(True) self.builder.get_object('beamstop_out_button').set_sensitive(False) else: self.builder.get_object('beamstopstate_image').set_from_icon_name('beamstop-inconsistent', Gtk.IconSize.BUTTON) self.builder.get_object('beamstop_in_button').set_sensitive(True) self.builder.get_object('beamstop_out_button').set_sensitive(True) return False
def _move(self, up=False): text = self._search_entry.get_text() if not text: return if up and self.__selected_search_result == 1: return False model = self._treeview.get_model() selection = self._treeview.get_selection() # disable flush timeout while searching if self._entry_flush_timeout: GLib.source_remove(self._entry_flush_timeout) self._entry_flush_timeout = 0 # search start_count = self.__selected_search_result + (-1 if up else 1) start_iter = model.get_iter_first() found_iter = self.search_iter(selection, start_iter, text, 0, start_count) if found_iter: self.__selected_search_result += (-1 if up else 1) return True else: # Return to old iter self.search_iter(selection, start_iter, text, 0, self.__selected_search_result) return False # renew flush timeout self._renew_flush_timeout() return
def checkFiles( self ): for monitored in self.monitoredFiles: if monitored.hasChanged(): if monitored.args: GLib.idle_add( monitored.callback, monitored.args ) else: GLib.idle_add( monitored.callback )
def _expand_node_by_name(self, search_num, parent, name, rest=None): """ Recursive function to expand all nodes in a hierarchical list of names. @param search_num: the current search number @param parent: the parent node @param name: the name of the node to expand @param rest: the list of the nodes to expand after this one """ iter = self.model.iter_children(parent) while iter: if search_num != self._search_num: return value = self.model.get_value(iter, 1) if not value: value = self.model.get_value(iter, 2) if value: value = unicode(value, 'utf-8') if value == name: self.tree.expand_row(self.model.get_path(iter), False) parent = iter break iter = self.model.iter_next(iter) if rest: item = rest.pop(0) GLib.idle_add(self._expand_node_by_name, search_num, parent, item, rest)
def _updatePositionCb(self, unused_pipeline, position): """Updates the progress bar and triggers the update of the file size. This one occurs every time the pipeline emits a position changed signal, which is *very* often. """ self.current_position = position if not self.progress or not position: return length = self.project.ges_timeline.props.duration fraction = float(min(position, length)) / float(length) self.progress.updatePosition(fraction) # In order to have enough averaging, only display the ETA after 5s timediff = time.time() - self._time_started if not self._timeEstimateTimer: if timediff < 6: self.progress.progressbar.set_text(_("Estimating...")) else: self._timeEstimateTimer = GLib.timeout_add_seconds( 3, self._updateTimeEstimateCb) # Filesize is trickier and needs more time to be meaningful. if not self._filesizeEstimateTimer and (fraction > 0.33 or timediff > 180): self._filesizeEstimateTimer = GLib.timeout_add_seconds( 5, self._updateFilesizeEstimateCb)
def do_activate(self): try: from gi.repository import AppIndicator3 as appindicator except ImportError: logger.exception(ImportError) return if hasattr(self, 'ind'): self.ind.set_status(appindicator.IndicatorStatus.ACTIVE) self.timer_id = GLib.timeout_add_seconds(5, self.update) return self.date = datetime.date.today() self.app = self.object self.settings = Gio.Settings.new('org.gahshomar.Gahshomar') self.date_format = str(self.settings.get_value('persian-date-format')) self.date_format = self.date_format.replace("'", "") self.ind = appindicator.Indicator.new( "GahShomar-indicator", 'org.gahshomar.Gahshomar-no-icon', appindicator.IndicatorCategory.APPLICATION_STATUS) self.ind.set_status(appindicator.IndicatorStatus.ACTIVE) self.menu_setup() self.update() self.timer_id = GLib.timeout_add_seconds(5, self.update)
def _get_tracks_files(self): """ Return children uris for uri @return [str] """ children = [] dir_uris = [self._uri+'/tracks/'] while dir_uris: uri = dir_uris.pop(0) album_name = uri.replace(self._uri+"/tracks/", "") album = GLib.uri_escape_string(album_name, "", False) d = Gio.File.new_for_uri(self._uri+"/tracks/"+album) infos = d.enumerate_children( 'standard::name,standard::type', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, None) for info in infos: if info.get_file_type() == Gio.FileType.DIRECTORY: dir_uris.append(uri+info.get_name()) else: track = GLib.uri_escape_string(info.get_name(), "", False) children.append("%s/tracks/%s/%s" % (self._uri, album, track)) return children
def _stop_and_maybe_start_time_updating(self, interval=2): """ This method is called in every date/time-setting button's callback. It removes the timer for updating displayed date/time (do not want to change it while user does it manually) and allows us to set new system date/time only after $interval seconds long idle on time-setting buttons. This is done by the _start_updating_timer that is reset in this method. So when there is $interval seconds long idle on date/time-setting buttons, self._save_system_time method is invoked. Since it returns False, this timer is then removed and only reactivated in this method (thus in some date/time-setting button's callback). """ #do not start timers if the spoke is not shown if self._update_datetime_timer_id is None: self._update_datetime() self._save_system_time() return #stop time updating GLib.source_remove(self._update_datetime_timer_id) #stop previous $interval seconds timer (see below) if self._start_updating_timer_id: GLib.source_remove(self._start_updating_timer_id) #let the user change date/time and after $interval seconds of inactivity #save it as the system time and start updating the displayed date/time self._start_updating_timer_id = GLib.timeout_add_seconds(interval, self._save_system_time)
def __init__(self): super().__init__({ application_id: 'org.gnome.Music', flags: gio.ApplicationFlags.FLAGS_NONE, inactivity_timeout: 12000} ) GLib.set_application_name("Music")
def enabled(self): if not self.running: wm = WatchManager() self.event_handler = LibraryEvent(app.library) # Choose event types to watch for # FIXME: watch for IN_CREATE or for some reason folder copies # are missed, --nickb FLAGS = ['IN_DELETE', 'IN_CLOSE_WRITE',# 'IN_MODIFY', 'IN_MOVED_FROM', 'IN_MOVED_TO', 'IN_CREATE'] mask = reduce(lambda x, s: x | EventsCodes.ALL_FLAGS[s], FLAGS, 0) if self.USE_THREADS: print_d("Using threaded notifier") self.notifier = ThreadedNotifier(wm, self.event_handler) # Daemonize to ensure thread dies on exit self.notifier.daemon = True self.notifier.start() else: self.notifier = Notifier(wm, self.event_handler, timeout=100) GLib.timeout_add(1000, self.unthreaded_callback) for path in get_scan_dirs(): print_d('Watching directory %s for %s' % (path, FLAGS)) # See https://github.com/seb-m/pyinotify/wiki/ # Frequently-Asked-Questions wm.add_watch(path, mask, rec=True, auto_add=True) self.running = True
def _busMessageCb(self, unused_bus, message): if message.type == Gst.MessageType.EOS: self.pause() self.emit('eos') elif message.type == Gst.MessageType.STATE_CHANGED: prev, new, pending = message.parse_state_changed() if message.src == self._pipeline: self.debug("Pipeline change state prev:%r, new:%r, pending:%r" % (prev, new, pending)) emit_state_change = pending == Gst.State.VOID_PENDING if prev == Gst.State.READY and new == Gst.State.PAUSED: # trigger duration-changed try: self.getDuration() except PipelineError: # no sinks?? pass elif prev == Gst.State.PAUSED and new == Gst.State.PLAYING: self._listenToPosition(True) elif prev == Gst.State.PLAYING and new == Gst.State.PAUSED: self._listenToPosition(False) if emit_state_change: self.emit('state-change', new) elif message.type == Gst.MessageType.ERROR: error, detail = message.parse_error() self._handleErrorMessage(error, detail, message.src) elif message.type == Gst.MessageType.DURATION_CHANGED: self.debug("Duration might have changed, querying it") GLib.idle_add(self._queryDurationAsync) else: self.log("%s [%r]" % (message.type, message.src))
def on_playback_track_end(self, event, player, track): """ Stops marker watching """ if self.__timeout_id is not None: GLib.source_remove(self.__timeout_id) self.__timeout_id = None