def start_transfer_op(self, op): logging.debug("Remote RPC: calling StartTransfer on '%s'" % (self.display_hostname)) start_time = GLib.get_monotonic_time() op.progress_tracker = transfers.OpProgressTracker(op) op.current_progress_report = None receiver = transfers.FileReceiver(op) op.set_status(OpStatus.TRANSFERRING) op.file_iterator = self.stub.StartTransfer( warp_pb2.OpInfo(timestamp=op.start_time, ident=self.local_ident, readable_name=util.get_hostname(), use_compression=op.use_compression and prefs.use_compression())) def report_receive_error(error): op.set_error(error) try: # If we leave an io stream open, it locks the location. For instance, # if this was a mounted location, we wouldn't be able to terminate until # we closed warp. if receiver.current_stream != None: receiver.current_stream.close() except GLib.Error: pass logging.critical("An error occurred receiving data from %s: %s" % (op.sender, op.error_msg)) op.set_status(OpStatus.FAILED) op.stop_transfer() try: for data in op.file_iterator: receiver.receive_data(data) except grpc.RpcError: if op.file_iterator.code() == grpc.StatusCode.CANCELLED: op.file_iterator = None return else: report_receive_error(op.file_iterator) return except Exception as e: report_receive_error(e) return op.file_iterator = None receiver.receive_finished() logging.debug("Remote: receipt of %s files (%s) finished in %s" % \ (op.total_count, GLib.format_size(op.total_size),\ util.precise_format_time_span(GLib.get_monotonic_time() - start_time))) op.set_status(OpStatus.FINISHED)
def do_render(self, ctx, widget, background_area, cell_area, flags): if not self.image: return if self.image.get_storage_type() == Gtk.ImageType.ANIMATION: if self.image not in self.iters: if not isinstance(widget, Gtk.TreeView): return animation = self.image.get_animation() timeval = GLib.TimeVal() timeval.tv_sec = GLib.get_monotonic_time() / 1000000 iter_ = animation.get_iter(timeval) self.iters[self.image] = iter_ GLib.timeout_add(iter_.get_delay_time(), self.animation_timeout, widget, self.image) pix = self.iters[self.image].get_pixbuf() elif self.image.get_storage_type() == Gtk.ImageType.PIXBUF: pix = self.image.get_pixbuf() else: return calc_width = self.get_property('xpad') * 2 + pix.get_width() calc_height = self.get_property('ypad') * 2 + pix.get_height() x_pos = cell_area.x + self.get_property('xalign') * \ (cell_area.width - calc_width - self.get_property('xpad')) y_pos = cell_area.y + self.get_property('yalign') * \ (cell_area.height - calc_height - self.get_property('ypad')) Gdk.cairo_set_source_pixbuf(ctx, pix, x_pos, y_pos) ctx.paint()
def _queue_files(self, request): self.start_time = GLib.get_monotonic_time() self.interval_start_time = self.start_time self.current_transfer_size = 0 for queued_file in request.files: self.queue.put(queued_file)
def StartTransfer(self, request, context): start_time = GLib.get_monotonic_time() op = self.remote_machines[request.connect_name].lookup_op( request.timestamp) cancellable = threading.Event() op.file_send_cancellable = cancellable op.set_status(OpStatus.TRANSFERRING) op.progress_tracker = transfers.OpProgressTracker(op) op.current_progress_report = None sender = transfers.FileSender(op, self.service_name, request.timestamp, cancellable) def transfer_done(): if sender.error != None: op.set_error(sender.error) op.stop_transfer() op.set_status(OpStatus.FAILED_UNRECOVERABLE) elif op.file_send_cancellable.is_set(): print("File send cancelled") else: print("Transfer of %s files (%s) finished in %s" % \ (op.total_count, GLib.format_size(op.total_size),\ util.precise_format_time_span(GLib.get_monotonic_time() - start_time))) context.add_callback(transfer_done) return sender.read_chunks()
def __init__(self, mark0, mark1, rgba0, rgba1, duration): self.start_mark = mark0 self.end_mark = mark1 self.start_rgba = rgba0 self.end_rgba = rgba1 self.start_time = GLib.get_monotonic_time() self.duration = duration
def on_startup(self): # Start the sqlite driver sqlite.start() # Initialize application menu actions = [('synchronize', self.on_sync), ('subscribe', self.on_subscribe), ('about', self.on_show_about), ('preferences', self.on_show_prefs), ('quit', lambda *x: self.quit())] for action, cb in actions: action = Gio.SimpleAction.new(action, None) action.connect('activate', cb) self.add_action(action) builder = Gtk.Builder(translation_domain='trifle') builder.add_from_file(get_data_path('ui', 'app-menu.ui')) self.set_app_menu(builder.get_object('app-menu')) # Check for need to refresh every 60 seconds. GLib.timeout_add_seconds(60, self.on_sync_timeout) self.last_sync = GLib.get_monotonic_time() if models.settings.settings['start-refresh']: self.on_sync(None) # Load application styles css_provider = Gtk.CssProvider() css_provider.load_from_path(get_data_path('ui', 'trifle-style.css')) ctx = Gtk.StyleContext() ctx.add_provider_for_screen(Gdk.Screen.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
def update_progress(self, size_read): self.total_transferred += size_read now = GLib.get_monotonic_time() if ((now - self.last_update_time) > util.PROGRESS_UPDATE_FREQ): self.last_update_time = now progress = self.total_transferred / self.total_size elapsed = now - self.transfer_start_time bytes_per_micro = self.total_transferred / elapsed bytes_per_sec = int(bytes_per_micro * 1000 * 1000) if bytes_per_sec == 0: bytes_per_sec = 1 # no a/0 time_left_sec = (self.total_size - self.total_transferred) / bytes_per_sec print("%s time left, %s/s" % (util.format_time_span(time_left_sec), GLib.format_size(bytes_per_sec))) progress_report = Progress(progress, time_left_sec, bytes_per_sec) self.op.progress_report(progress_report)
def _update_progress(self, cb_info): if cb_info.finished: with self.proxy.lock: # Don't send NeverStartedSending errors to the other end. if cb_info.error and isinstance(cb_info.error, Aborted): e_str = str(cb_info.error) else: e_str = None self.proxy.update_progress(self.app_name, 0, "", "", cb_info.finished, e_str) GLib.idle_add(self.progress_callback, cb_info, priority=GLib.PRIORITY_DEFAULT) print("finished: %s" % util.precise_format_time_span(GLib.get_monotonic_time() - self.start_time)) return if cb_info.is_informational(): GLib.idle_add(self.progress_callback, cb_info, priority=GLib.PRIORITY_DEFAULT) return cb_info.progress = self.current_transfer_size / self.total_transfer_size cur_time = GLib.get_monotonic_time() total_elapsed = cur_time - self.start_time if (cur_time - self.interval_start_time) > self.PROGRESS_INTERVAL: self.interval_start_time = cur_time bytes_per_micro = self.current_transfer_size / total_elapsed bytes_per_sec = int(bytes_per_micro * 1000 * 1000) bytes_left = self.total_transfer_size - self.current_transfer_size time_left_sec = bytes_left / bytes_per_sec cb_info.speed = _("%s/s") % GLib.format_size(bytes_per_sec) cb_info.time_left = util.format_time_span(time_left_sec) with self.proxy.lock: self.proxy.update_progress(self.app_name, cb_info.progress, cb_info.speed, cb_info.time_left, cb_info.finished, None) GLib.idle_add(self.progress_callback, cb_info, priority=GLib.PRIORITY_DEFAULT)
def make_symbolic_link(op, path, target): tmppath = os.path.join( os.path.dirname(path), "%s-%d-%d.tmp" % (op.sender, op.start_time, GLib.get_monotonic_time())) tmpfile = Gio.File.new_for_path(tmppath) tmpfile.make_symbolic_link(target, None) os.replace(tmpfile.get_path(), path)
def __on_activate(self, application): """ Call default handler @param application as Gio.Application """ # https://bugzilla.gnome.org/show_bug.cgi?id=766284 monotonic_time = int(GLib.get_monotonic_time() / 1000) self.window.present_with_time(monotonic_time)
def on_sync_timeout(self): current = GLib.get_monotonic_time() refresh_every = models.settings.settings['refresh-every'] # Setting 'refresh-every' value 0 stands for Never if refresh_every == 0: self.last_sync = current return True if current - self.last_sync > refresh_every * 6E7: self.on_sync(None) return True
def transfer_done(): if sender.error != None: op.set_error(sender.error) op.stop_transfer() op.set_status(OpStatus.FAILED_UNRECOVERABLE) elif op.file_send_cancellable.is_set(): print("File send cancelled") else: print("Transfer of %s files (%s) finished in %s" % \ (op.total_count, GLib.format_size(op.total_size),\ util.precise_format_time_span(GLib.get_monotonic_time() - start_time)))
def do_activate(self): if not self._window: self._window = Window(self) self._window.set_default_icon_name(self._application_id) if self._application_id == 'org.gnome.MusicDevel': self._window.get_style_context().add_class('devel') MediaPlayer2Service(self) # gtk_window_present does not work on Wayland. # Use gtk_present_with_time as a workaround instead. # See https://gitlab.gnome.org/GNOME/gtk/issues/624#note_10996 self._window.present_with_time(GLib.get_monotonic_time() / 1000)
def touch_event_cb(widget, event, drawing): global TOUCH_BEGIN global TOUCH_TIME x1, y1 = GRAPH_X_START + GRAPH_WIDTH - LOGO_WIDTH - 10, GRAPH_Y_START + LOGO_HEIGHT - 10 x2, y2 = x1 + LOGO_WIDTH, y1 + LOGO_HEIGHT coords = event.get_coords() if coords[0] is True and (coords[1] >= x1 and coords[2] >= y1) and \ (coords[1] <= x2 and coords[2] <= y2): if event.type == Gdk.EventType.TOUCH_BEGIN: if TOUCH_BEGIN is False: TOUCH_BEGIN = True TOUCH_TIME = GLib.get_monotonic_time() if event.type == Gdk.EventType.TOUCH_UPDATE: if TOUCH_BEGIN is True: if GLib.get_monotonic_time() - TOUCH_TIME >= 1000000: start_thread(drawing, True) TOUCH_BEGIN = False if event.type == Gdk.EventType.TOUCH_END: TOUCH_BEGIN = False return False
def __on_command_line(self, app, app_cmd_line): """ Handle command line @param app as Gio.Application @param options as Gio.ApplicationCommandLine """ self.__externals_count = 0 args = app_cmd_line.get_arguments() options = app_cmd_line.get_options_dict() if options.contains("show-tls"): self.show_tls = True if options.contains("disable-artwork-cache"): self.art.disable_cache() ephemeral = options.contains("private") if not self.get_windows(): self.__create_initial_windows(len(args) < 2) active_window = self.active_window elif options.contains("new") or len(args) == 1: active_window = self.get_new_window() else: active_window = self.active_window # Open command line args if len(args) > 1: items = [] i = 0 for uri in args[1:]: # Transform path to uri parsed = urlparse(uri) if not parsed.scheme: if uri.startswith('/'): uri = "file://%s" % uri else: uri = "http://%s" % uri loading_type = wanted_loading_type(i) items.append((uri, uri, 0, ephemeral, None, loading_type)) i += 1 active_window.container.add_webviews(items) # https://bugzilla.gnome.org/show_bug.cgi?id=766284 monotonic_time = int(GLib.get_monotonic_time() / 1000) active_window.present_with_time(monotonic_time) # Add default start page if not active_window.container.views: active_window.container.add_webview(self.start_page, LoadingType.FOREGROUND, ephemeral) if self.settings.get_value("debug"): WebKit2.WebContext.get_default().get_plugins( None, self.__on_get_plugins, None) Gdk.notify_startup_complete() return 0
def add_ops(machine): TEST_OPS.reverse() for entry in TEST_OPS: op_type, sender, receiver, status, time, size, count, sender_disp_name, receiver_disp_name, name_if_single, special_condition = entry if op_type == "send": op = ops.SendOp(sender=sender, receiver=receiver, receiver_name=receiver_disp_name, uris=[]) machine.add_op(op) f = transfers.File(name_if_single, name_if_single, "fixme", 50, FileType.REGULAR, None) op.top_dir_basenames = [name_if_single, "bar"] op.resolved_files = [f] op.total_size = size op.total_count = count op.first_missing_file = name_if_single op.name_if_single = name_if_single op.mime_if_single, uncertainty = Gio.content_type_guess( op.name_if_single, None) op.file_send_cancellable = Dummy() if status != OpStatus.CALCULATING: op.update_ui_info(True) idle_set_op_status((op, status)) elif op_type == "receive": op = ops.ReceiveOp(sender=sender) op.start_time = GLib.get_monotonic_time() op.receiver = receiver op.sender_name = sender_disp_name op.receiver_name = receiver_disp_name op.total_size = size op.top_dir_basenames = [name_if_single, "bar"] op.total_count = count op.name_if_single = name_if_single op.mime_if_single, uncertainty = Gio.content_type_guess( op.name_if_single, None) op.file_iterator = Dummy() machine.add_op(op) op.prepare_receive_info() if special_condition == "overwrite": op.existing = True elif special_condition == "nospace": op.have_space = False idle_set_op_status((op, status))
def animation_timeout(self, tree, image): if image.get_storage_type() != Gtk.ImageType.ANIMATION: return self.redraw = 0 iter_ = self.iters[image] timeval = GLib.TimeVal() timeval.tv_sec = GLib.get_monotonic_time() / 1000000 iter_.advance(timeval) model = tree.get_model() if model: model.foreach(self.func, (image, tree)) if self.redraw: GLib.timeout_add(iter_.get_delay_time(), self.animation_timeout, tree, image) elif image in self.iters: del self.iters[image]
def get_libraries(self): now = GLib.get_monotonic_time() if now < self._libraries_expire_at: return self._libraries self._libraries = [] self._libraries_expire_at = now + CACHE_EXPIRE_USEC for directory in GIRepository.Repository.get_search_path(): for filename in os.listdir(directory): name = filename.split('-')[0] if name not in self._libraries: self._libraries.append(name) self._libraries.sort() return self._libraries
def add(self, value_1: float, value_2: float): row = self.model.push(GLib.get_monotonic_time()) self.model.iter_set(row, 0, value_1) self.model.iter_set(row, 1, value_2) self.db[0].append(value_1) self.db[1].append(value_2) if len(self.db[0]) > 120: self.db[0].pop(0) self.db[1].pop(0) value_1_max = max(self.db[0]) value_2_max = max(self.db[1]) self.model.props.value_max = value_1_max if value_1_max > value_2_max else value_2_max
def StartTransfer(self, request, context): logging.debug("Server RPC: StartTransfer from '%s'" % request.readable_name) start_time = GLib.get_monotonic_time() try: remote = self.remote_machines[request.ident] except KeyError as e: logging.warning( "Server: start transfer is from unknown remote: %s" % e) return try: op = self.remote_machines[request.ident].lookup_op( request.timestamp) except KeyError as e: logging.warning("Server: start transfer for unknowns op: %s" % e) return cancellable = threading.Event() op.file_send_cancellable = cancellable op.set_status(OpStatus.TRANSFERRING) op.progress_tracker = transfers.OpProgressTracker(op) op.current_progress_report = None sender = transfers.FileSender(op, request.timestamp, cancellable) def transfer_done(): if sender.error != None: op.set_error(sender.error) op.stop_transfer() op.set_status(OpStatus.FAILED_UNRECOVERABLE) elif op.file_send_cancellable.is_set(): logging.debug("Server: file send cancelled") else: logging.debug("Server: transfer of %s files (%s) finished in %s" % \ (op.total_count, GLib.format_size(op.total_size),\ util.precise_format_time_span(GLib.get_monotonic_time() - start_time))) context.add_callback(transfer_done) return sender.read_chunks()
def get_libraries(self): now = GLib.get_monotonic_time() if now < self._libraries_expire_at: return self._libraries self._libraries = [] self._libraries_expire_at = now + CACHE_EXPIRE_USEC found = {} for directory in GIRepository.Repository.get_search_path(): if os.path.exists(directory): for filename in os.listdir(directory): name = filename.split('-')[0] if name not in found: self._libraries.append(CompletionProposal(name)) found[name] = None self._libraries.sort(key=lambda x: x.completion) return self._libraries
def on_decide_policy_cb(self, webview, decision, decision_type): """Handle policy decisions from webview""" if decision_type == WebKit2.PolicyDecisionType.NAVIGATION_ACTION: # Don't allow navigating away from the current page action = decision.get_navigation_action() request = action.get_request() uri = request.get_uri() # print(">>> URI = ", uri) if uri != self.document.get_file().get_uri() \ and 'gnome-builder-sphinx' not in uri: toplevel = self.webview.get_toplevel() Ide.gtk_show_uri_on_window(toplevel, uri, GLib.get_monotonic_time()) decision.ignore() return True return False
def __init__(self, direction, sender, uris=None): super(CommonOp, self).__init__() self.uris = uris self.sender = sender self.direction = direction self.status = OpStatus.INIT self.start_time = GLib.get_monotonic_time( ) # for sorting in the op list self.total_size = 0 self.total_count = 0 self.size_string = "" self.description = "" self.name_if_single = None self.mime_if_single = "application/octet-stream" # unknown self.gicon = Gio.content_type_get_symbolic_icon(self.mime_if_single) self.error_msg = "" self.progress_tracker = None
def do_get_preferred_width(self, widget): """ Return the width we need for this cell. Each cell is drawn individually and is only as wide as it needs to be, we let the TreeViewColumn take care of making them all line up. """ if not self.image: return 0, 0 if self.image.get_storage_type() == Gtk.ImageType.ANIMATION: animation = self.image.get_animation() timeval = GLib.TimeVal() timeval.tv_sec = GLib.get_monotonic_time() / 1000000 pix = animation.get_iter(timeval).get_pixbuf() elif self.image.get_storage_type() == Gtk.ImageType.PIXBUF: pix = self.image.get_pixbuf() else: return 0, 0, 0, 0 calc_width = self.get_property('xpad') * 2 + pix.get_width() return calc_width, calc_width
def _init_graphs(self) -> None: if is_dazzle_version_supported(): self._graph_views: Dict[GraphType, Tuple[Gtk.Label, Gtk.Label, Gtk.Label]] = {} self._graph_models: Dict[GraphType, Dazzle.GraphModel] = {} for graph_type in GraphType: self._graph_container: Gtk.Frame = self._builder.get_object(f'graph_container_{graph_type.value}') self._graph_views[graph_type] = (self._builder.get_object(f'graph_min_value_{graph_type.value}'), self._builder.get_object(f'graph_max_value_{graph_type.value}'), self._builder.get_object(f'graph_max_axis_{graph_type.value}')) graph_views = Dazzle.GraphView() graph_model = Dazzle.GraphModel() graph_renderer = GraphStackedRenderer() graph_views.set_hexpand(True) graph_views.props.height_request = 80 graph_renderer.set_line_width(1.5) stroke_color = Gdk.RGBA() stroke_color.parse(GRAPH_COLOR_HEX) stacked_color = Gdk.RGBA() stacked_color.parse(GRAPH_COLOR_HEX) stacked_color.alpha = 0.5 graph_renderer.set_stroke_color_rgba(stroke_color) graph_renderer.set_stacked_color_rgba(stacked_color) graph_model.set_timespan(MONITORING_INTERVAL * 1000 * 1000) graph_model.set_max_samples(MONITORING_INTERVAL / self._presenter.get_refresh_interval() + 1) graph_model.props.value_max = 100.0 graph_model.props.value_min = 0.0 column_ram = Dazzle.GraphColumn().new("Col0", TYPE_DOUBLE) graph_model.add_column(column_ram) graph_views.set_model(graph_model) graph_views.add_renderer(graph_renderer) self._graph_container.add(graph_views) graph_model_iter = graph_model.push(GLib.get_monotonic_time()) graph_model.iter_set(graph_model_iter, 0, 0.0) self._graph_models[graph_type] = graph_model
def select(self, timeout=None): may_block = True self._source.set_ready_time(-1) if timeout is not None: if timeout > 0: self._source.set_ready_time(GLib.get_monotonic_time() + int(timeout * 1000000)) else: may_block = False self._source.clear() if may_block: g_main_loop_run(self._main_loop) else: self._context.iteration(False) ready = [] for key in self.get_map().values(): events = self._source.get_events(key.fd) & key.events if events != 0: ready.append((key, events)) return ready
def add_status(self, new_status: Status, gpu_index: int) -> None: if is_dazzle_version_supported(): if self._gpu_index != gpu_index: self._gpu_index = gpu_index self.view.reset_graphs() data: Dict[GraphType, Tuple[int, float, str, float, float]] = {} time = GLib.get_monotonic_time() gpu_status = new_status.gpu_status_list[gpu_index] gpu_clock = gpu_status.clocks.graphic_current if gpu_clock is not None: data[GraphType.GPU_CLOCK] = (time, float(gpu_clock), 'MHz', 0.0, 2000.0) mem_clock = gpu_status.clocks.memory_current if mem_clock is not None: data[GraphType.MEMORY_CLOCK] = (time, float(mem_clock), 'MHz', 0.0, 7000.0) gpu_temp = gpu_status.temp.gpu if gpu_temp is not None: data[GraphType.GPU_TEMP] = (time, float(gpu_temp), '°C', 0.0, 100.0) if gpu_status.fan.fan_list: fan_duty = gpu_status.fan.fan_list[0][0] data[GraphType.FAN_DUTY] = (time, float(fan_duty), '%', 0.0, 100.0) fan_rpm = gpu_status.fan.fan_list[0][1] data[GraphType.FAN_RPM] = (time, float(fan_rpm), 'rpm', 0.0, 2200.0) gpu_load = gpu_status.info.gpu_usage if gpu_load is not None: data[GraphType.GPU_LOAD] = (time, float(gpu_load), '%', 0.0, 100.0) mem_load = gpu_status.info.memory_usage if mem_load is not None: data[GraphType.MEMORY_LOAD] = (time, float(mem_load), '%', 0.0, 100.0) mem_usage = gpu_status.info.memory_used if mem_usage is not None: data[GraphType.MEMORY_USAGE] = (time, float(mem_usage), 'MiB', 0.0, float(gpu_status.info.memory_total)) power_draw = gpu_status.power.draw maximum = gpu_status.power.maximum if power_draw is not None: data[GraphType.POWER_DRAW] = (time, power_draw, 'W', 0.0, 400 if maximum is None else maximum) self.view.refresh_graphs(data)
def refresh_graphs(self, data_dict: Dict[GraphType, Tuple[int, float, str, float, float]]) -> None: time1 = time.time() for graph_type, data_tuple in data_dict.items(): max_value = self._graph_models[graph_type].props.value_max self._graph_models[graph_type].props.value_max = max(data_tuple[4], max_value) graph_model_iter = self._graph_models[graph_type].push(GLib.get_monotonic_time()) self._graph_models[graph_type].iter_set(graph_model_iter, 0, data_tuple[1]) self._graph_views[graph_type][2].set_text(f"{data_tuple[1]:.0f} {data_tuple[2]}") model_iter = Dazzle.GraphModelIter() if self._dialog.props.visible and self._graph_models[graph_type].get_iter_first(model_iter): min_value = data_tuple[4] * 10 max_value = data_tuple[3] while Dazzle.GraphModel.iter_next(iter=model_iter): gval = GObject.Value() Dazzle.GraphModel.iter_get_value(iter=model_iter, column=0, value=gval) val = gval.get_double() min_value = min(val, min_value) max_value = max(val, max_value) self._graph_views[graph_type][0].set_text(f"{min_value:.0f}") self._graph_views[graph_type][1].set_text(f"{max_value:.0f}") self._graph_models[graph_type].props.value_max = max(data_tuple[4], max_value) time2 = time.time() LOG.debug(f'Refresh graph took {((time2 - time1) * 1000.0):.3f} ms')
def on_usage(self, obj, spec): it = self.table.push(GLib.get_monotonic_time()) it.set_column(0, self.gpu.props.usage)
def __init__(self, op): self.op = op self.total_size = op.total_size self.total_transferred = 0 self.transfer_start_time = GLib.get_monotonic_time() self.last_update_time = self.transfer_start_time
def time(self): return GLib.get_monotonic_time() / 1000000
def do_draw_layer(self, layer, context): if layer != Gtk.TextViewLayer.BELOW_TEXT: return GtkSource.View.do_draw_layer(self, layer, context) context.save() context.set_line_width(1.0) _, clip = Gdk.cairo_get_clip_rectangle(context) clip_end = clip.y + clip.height bounds = ( self.get_line_num_for_y(clip.y), self.get_line_num_for_y(clip_end), ) x = clip.x - 0.5 width = clip.width + 1 # Paint chunk backgrounds and outlines for change in self.chunk_iter(bounds): ypos0 = self.get_y_for_line_num(change[1]) ypos1 = self.get_y_for_line_num(change[2]) height = max(0, ypos1 - ypos0 - 1) context.rectangle(x, ypos0 + 0.5, width, height) if change[1] != change[2]: context.set_source_rgba(*self.fill_colors[change[0]]) context.fill_preserve() if self.current_chunk_check(change): highlight = self.fill_colors['current-chunk-highlight'] context.set_source_rgba(*highlight) context.fill_preserve() context.set_source_rgba(*self.line_colors[change[0]]) context.stroke() textbuffer = self.get_buffer() # Check whether we're drawing past the last line in the buffer # (i.e., the overscroll) and draw a custom background if so. end_y, end_height = self.get_line_yrange(textbuffer.get_end_iter()) end_y += end_height visible_bottom_margin = clip_end - end_y if visible_bottom_margin > 0: context.rectangle(x + 1, end_y, width - 1, visible_bottom_margin) context.set_source_rgba(*self.fill_colors['overscroll']) context.fill() # Paint current line highlight if self.props.highlight_current_line_local and self.is_focus(): it = textbuffer.get_iter_at_mark(textbuffer.get_insert()) ypos, line_height = self.get_line_yrange(it) context.rectangle(x, ypos, width, line_height) context.set_source_rgba(*self.highlight_color) context.fill() # Draw syncpoint indicator lines for syncpoint in self.syncpoints: if syncpoint is None: continue syncline = textbuffer.get_iter_at_mark(syncpoint).get_line() if bounds[0] <= syncline <= bounds[1]: ypos = self.get_y_for_line_num(syncline) context.rectangle(x, ypos - 0.5, width, 1) context.set_source_rgba(*self.syncpoint_color) context.stroke() # Overdraw all animated chunks, and update animation states new_anim_chunks = [] for c in self.animating_chunks: current_time = GLib.get_monotonic_time() percent = min(1.0, (current_time - c.start_time) / float(c.duration)) rgba_pairs = zip(c.start_rgba, c.end_rgba) rgba = [s + (e - s) * percent for s, e in rgba_pairs] it = textbuffer.get_iter_at_mark(c.start_mark) ystart, _ = self.get_line_yrange(it) it = textbuffer.get_iter_at_mark(c.end_mark) yend, _ = self.get_line_yrange(it) if ystart == yend: ystart -= 1 context.set_source_rgba(*rgba) context.rectangle(x, ystart, width, yend - ystart) if c.anim_type == TextviewLineAnimationType.stroke: context.stroke() else: context.fill() if current_time <= c.start_time + c.duration: new_anim_chunks.append(c) else: textbuffer.delete_mark(c.start_mark) textbuffer.delete_mark(c.end_mark) self.animating_chunks = new_anim_chunks if self.animating_chunks and self.anim_source_id is None: def anim_cb(): self.queue_draw() return True # Using timeout_add interferes with recalculation of inline # highlighting; this mechanism could be improved. self.anim_source_id = GLib.idle_add(anim_cb) elif not self.animating_chunks and self.anim_source_id: GLib.source_remove(self.anim_source_id) self.anim_source_id = None context.restore() return GtkSource.View.do_draw_layer(self, layer, context)
def do_draw_layer(self, layer, context): if layer != Gtk.TextViewLayer.BELOW: return GtkSource.View.do_draw_layer(self, layer, context) context.save() context.set_line_width(1.0) _, clip = Gdk.cairo_get_clip_rectangle(context) _, buffer_y = self.window_to_buffer_coords( Gtk.TextWindowType.WIDGET, 0, clip.y) _, buffer_y_end = self.window_to_buffer_coords( Gtk.TextWindowType.WIDGET, 0, clip.y + clip.height) bounds = (self.get_line_num_for_y(buffer_y), self.get_line_num_for_y(buffer_y_end)) visible = self.get_visible_rect() x = clip.x - 0.5 width = clip.width + 1 # Paint chunk backgrounds and outlines for change in self.chunk_iter(bounds): ypos0 = self.get_y_for_line_num(change[1]) - visible.y ypos1 = self.get_y_for_line_num(change[2]) - visible.y height = max(0, ypos1 - ypos0 - 1) context.rectangle(x, ypos0 + 0.5, width, height) if change[1] != change[2]: context.set_source_rgba(*self.fill_colors[change[0]]) context.fill_preserve() if self.current_chunk_check(change): highlight = self.fill_colors['current-chunk-highlight'] context.set_source_rgba(*highlight) context.fill_preserve() context.set_source_rgba(*self.line_colors[change[0]]) context.stroke() textbuffer = self.get_buffer() # Paint current line highlight if self.props.highlight_current_line_local and self.is_focus(): it = textbuffer.get_iter_at_mark(textbuffer.get_insert()) ypos, line_height = self.get_line_yrange(it) context.save() context.rectangle(x, ypos - visible.y, width, line_height) context.clip() context.set_source_rgba(*self.highlight_color) context.paint_with_alpha(0.25) context.restore() # Draw syncpoint indicator lines for syncpoint in self.syncpoints: if syncpoint is None: continue syncline = textbuffer.get_iter_at_mark(syncpoint).get_line() if bounds[0] <= syncline <= bounds[1]: ypos = self.get_y_for_line_num(syncline) - visible.y context.rectangle(x, ypos - 0.5, width, 1) context.set_source_rgba(*self.syncpoint_color) context.stroke() # Overdraw all animated chunks, and update animation states new_anim_chunks = [] for c in self.animating_chunks: current_time = GLib.get_monotonic_time() percent = min( 1.0, (current_time - c.start_time) / float(c.duration)) rgba_pairs = zip(c.start_rgba, c.end_rgba) rgba = [s + (e - s) * percent for s, e in rgba_pairs] it = textbuffer.get_iter_at_mark(c.start_mark) ystart, _ = self.get_line_yrange(it) it = textbuffer.get_iter_at_mark(c.end_mark) yend, _ = self.get_line_yrange(it) if ystart == yend: ystart -= 1 context.set_source_rgba(*rgba) context.rectangle(x, ystart - visible.y, width, yend - ystart) context.fill() if current_time <= c.start_time + c.duration: new_anim_chunks.append(c) else: textbuffer.delete_mark(c.start_mark) textbuffer.delete_mark(c.end_mark) self.animating_chunks = new_anim_chunks if self.animating_chunks and self.anim_source_id is None: def anim_cb(): self.queue_draw() return True # Using timeout_add interferes with recalculation of inline # highlighting; this mechanism could be improved. self.anim_source_id = GLib.idle_add(anim_cb) elif not self.animating_chunks and self.anim_source_id: GLib.source_remove(self.anim_source_id) self.anim_source_id = None context.restore() return GtkSource.View.do_draw_layer(self, layer, context)
def treeview_button_press(self, widget, event): # Based on Nautilus button-press-event callback # https://git.gnome.org/browse/nautilus/tree/src/nautilus-list-view.c # click_count = 0 tv = widget sel = tv.get_selection() on_expander = False # Don't handle extra mouse button here if event.button > 5: return False if event.window != tv.get_bin_window(): return False # Not implementing nautilus_list_model_set_drag_view call double_click_time = tv.get_settings().get_default().get_property('gtk-double-click-time') # Determine click count current_time = GLib.get_monotonic_time() if current_time - self.last_click_time < double_click_time: click_count = click_count + 1 else: click_count = 0 # Stash time for next compare self.last_click_time = current_time # Not implementing nautilus single click mode self.details.ignore_button_release = False is_simple_click = ((event.button == 1 or event.button == 2) and (event.type == Gdk.EventType.BUTTON_PRESS)) ret = tv.get_path_at_pos(event.x, event.y) if ret is None: if is_simple_click: self.details.double_click_path[1] = self.details.double_click_path[0] self.details.double_click_path[0] = None # Deselect if people click outside any row. It's OK to let default # code run; it won't reselect anything. sel.unselect_all() tv.do_button_press_event(tv, event) if event.button == 3: return self.make_menu(event) return True (path, column, cell_x, cell_y) = ret call_parent = True path_selected = sel.path_is_selected(path) # Manage expander stuff expander_size = tv.style_get_property('expander-size') horizontal_separator = tv.style_get_property('horizontal-separator') # TODO we should not hardcode this extra padding. It is # EXPANDER_EXTRA_PADDING from GtkTreeView expander_size += 4 on_expander = (event.x <= horizontal_separator / 2 + path.get_depth() * expander_size) # Keep track of last click so double click only happen on the same item if is_simple_click: self.details.double_click_path[1] = self.details.double_click_path[0] self.details.double_click_path[0] = path.copy() if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS: # Double clicking does not trigger a DnD action self.details.drag_button = 0 if not on_expander and \ self.details.double_click_path[1] and not \ self.details.double_click_path[1].compare(self.details.double_click_path[0]): # Activate the cells on button 1 double-click tv.row_activated(path, column) else: tv.do_button_press_event(tv, event) else: # We're going to filter out some situations where we can't let # the default code run because all but one row would be deselected. # We don't want that; we want the right click menu or single click # to apply to everything that's currently selected. if event.button == 3 and path_selected: call_parent = False if (event.button == 1 or event.button == 2) and \ ((event.state & Gdk.ModifierType.CONTROL_MASK) or not\ (event.state & Gdk.ModifierType.SHIFT_MASK)): self.details.row_selected_on_button_down = path_selected if path_selected: call_parent = on_expander self.details.ignore_button_release = on_expander if event.state & Gdk.ModifierType.CONTROL_MASK: sel.unselect_path(path) elif event.state & Gdk.ModifierType.CONTROL_MASK: selected_rows = None l = None call_parent = False if event.state & Gdk.ModifierType.SHIFT_MASK: cursor = None (cursor, fc) = tv.get_cursor() if cursor is not None: sel.select_range(cursor, path) else: sel.select_path(path) else: sel.select_path(path) selected_rows = sel.get_selected_rows()[1] # This unselects everything tv.set_cursor(path, None, False) # So select it again for p in selected_rows: sel.select_path(p) else: self.details.ignore_button_release = on_expander if call_parent: tv.handler_block_by_func(self.row_activated) tv.do_button_press_event(tv, event) tv.handler_unblock_by_func(self.row_activated) elif path_selected: tv.grab_focus() if is_simple_click and not on_expander: self.details.drag_started = False self.details.drag_button = event.button self.details.drag_x = event.x self.details.drag_y = event.y if event.button == 3: # Popup menu return self.make_menu(event) return True