def _iterAction(self): ''' Iterate to the next sequence step. ''' if len(self.steps) <= self._current_step: if self._loop is not None: self._loop.quit() return action = self.steps[self._current_step] if self._verbose: print _('SEQUENCE: %s') % action try: next_action = self.steps[self._current_step + 1] except IndexError: next_action = None pyatspi.Registry.deregisterEventListener(self._onAnticipatedEvent, *self._anticipated_event_types) if isinstance(next_action, WaitAction): self._anticipated_event_types = next_action.wait_for else: self._anticipated_event_types = [] pyatspi.Registry.registerEventListener(self._onAnticipatedEvent, *self._anticipated_event_types) self._current_handler = action.connect('done', self._onStepDone) GObject.timeout_add(action.delta_time, self._doAction, action)
def arm (self, manager): self.manager = manager props = dict(obj=self.remote.path, name=self.remote.item.name, expected=self.when.isoformat( ), **self.remote.item.fields) self.props = props new_path = PATH + '/Scheduler/Armed/' + self.hashed delay_ms = (self.when - datetime.datetime.now( )).total_seconds( ) * 1000 self.remote.bus.add_signal_receiver(self.cleanup, "Remove", dbus_interface=Trigger.OWN_IFACE, bus_name=BUS, path=new_path) # manager.bus.add_signal_receiver(self.attrs, ack=self.on_success, error=self.on_error) trigger = None try: trigger = Trigger(new_path, manager, props, self) if trigger: trigger.Armed( ) self.manager.Trigger("Arming", trigger.path) self.trigger = trigger print "DELAYING", delay_ms gobject.timeout_add(delay_ms, trigger.Fire) manager.InterfacesAdded(trigger.path, { Trigger.OWN_IFACE: props }) self.manager.Trigger("Armed", trigger.path) except: print "already exited?" raise finally: pass return trigger
def clear_token_from_ubuntu_sso_sync(appname): """ send a dbus signal to the com.ubuntu.sso service to clear the credentials for the given appname, e.g. _("Ubuntu Software Center") and wait for it to finish (or 2s) """ from ubuntu_sso import ( DBUS_BUS_NAME, DBUS_CREDENTIALS_IFACE, DBUS_CREDENTIALS_PATH, ) # clean loop = GObject.MainLoop() bus = dbus.SessionBus() obj = bus.get_object(bus_name=DBUS_BUS_NAME, object_path=DBUS_CREDENTIALS_PATH, follow_name_owner_changes=True) proxy = dbus.Interface(object=obj, dbus_interface=DBUS_CREDENTIALS_IFACE) proxy.connect_to_signal("CredentialsCleared", loop.quit) proxy.connect_to_signal("CredentialsNotFound", loop.quit) proxy.connect_to_signal("CredentialsError", loop.quit) proxy.clear_credentials(appname, {}) # ensure we don't hang forever here GObject.timeout_add_seconds(2, loop.quit) # run the mainloop until the credentials are clear loop.run()
def __load_previous_file(self, scroll_to_end=True): if self._sub_file_number > 0: self.__load_file(self._sub_file_number - 1) if scroll_to_end is True: GObject.timeout_add(100, self.__scroll_to_end_of_loaded_file) else: self._previous_file_loaded = True
def main(): for opt in sys.argv[1:]: if opt in ('-h', '--help'): usage() sys.exit() elif opt in ('-d', '--dev'): config.ENABLE_INSPECTOR = True else: print "hotot: unrecognized option '%s'" % opt usage() sys.exit(1) try: import i18n except: from gettext import gettext as _ try: import prctl prctl.set_name('hotot') except: pass GObject.threads_init() config.loads(); agent.init_notify() app = Hotot() agent.app = app Gdk.threads_enter() Gtk.main() Gdk.threads_leave()
def on_realized(self, widget, data=None): if self.blinking and self.tick_id == 0: GObject.idle_add(self._blink_idle) trackers.con_tracker_get().disconnect(self, "realize", self.on_realized)
def set_blinking(self, blinking): self.blinking = blinking if blinking and self.tick_id == 0: GObject.idle_add(self._blink_idle) elif self.tick_id > 0: self.stop_blinking = True
def _button_clicked_cb(self, widget): self.set_enabled() if self.activity.player.is_playing(): self.activity.player.pause() self.set_button_play() GObject.source_remove(self._scale_update_id) self._scale_update_id = -1 else: if self.activity.player.error: self.set_disabled() else: if self.activity.player.player.props.current_uri is None: # There is no stream selected to be played # yet. Select the first one available = self.activity.playlist_widget.\ _items[0]['available'] if available: path = self.activity.playlist_widget._items[0]['path'] self.activity.playlist_widget.emit( 'play-index', 0, path) self.activity.playlist_widget.set_current_playing(0) else: self.activity.player.play() self.activity._switch_canvas(True) self._scale_update_id = GObject.timeout_add( self.SCALE_UPDATE_INTERVAL, self.__update_scale_cb)
def testAdd(self): self.hook = True e = E() e.connect('signal', self._callback) GObject.add_emission_hook(E, "signal", self._emission_hook) e.emit('signal') self.assertEqual(e.status, 3)
def __key_release_event_cb(self, window, event): if self.__is_alt(event) and self._alt_timeout_sid: self._home_box.set_resume_mode(True) GObject.source_remove(self._alt_timeout_sid) self._alt_timeout_sid = None return False
def on_autorefresh_toggled(self, autorefresh): if self.autorefresh_id != 0: GObject.source_remove(self.autorefresh_id) self.autorefresh_id = 0 if autorefresh.get_active(): self.autorefresh_id = GObject.timeout_add(AUTOREFRESH_TIMEOUT, self.on_refresh_chart, True)
def add_log_message(self, client_program_name, q_domain, domain_filter, action): """Add log message to the logs window""" self._logs_window.add_log_line(client_program_name, q_domain, domain_filter, action) color = ACTION_COLOR_MAP.get(action, ACTION_COLOR_MAP['default']) GObject.timeout_add(1000, self.set_blinker, color)
def find_books(self, search_text): if _NEW_TOOLBAR_SUPPORT: self.enable_button(False) else: self._books_toolbar.enable_button(False) self.clear_downloaded_bytes() textbuffer = self.textview.get_buffer() textbuffer.set_text(_('Performing lookup, please wait') + '...') self.book_selected = False self.ls.clear() search_tuple = search_text.lower().split() if len(search_tuple) == 0: self._alert(_('Error'), _('You must enter at least one search word.')) if _NEW_TOOLBAR_SUPPORT: self.search_entry.grab_focus() else: self._books_toolbar.search_entry.grab_focus() return FL = urllib.quote('fl[]') SORT = urllib.quote('sort[]') self.search_url = 'http://www.archive.org/advancedsearch.php?q=' + \ urllib.quote('(title:(' + search_text.lower() + ') OR creator:(' + search_text.lower() +')) AND format:(DJVU)') self.search_url += '&' + FL + '=creator&' + FL + '=description&' + FL + '=format&' + FL + '=identifier&' \ + FL + '=language' self.search_url += '&' + FL + '=publisher&' + FL + '=subject&' + FL + '=title&' + FL + '=volume' self.search_url += '&' + SORT + '=title&' + SORT + '&' + SORT + '=&rows=500&save=yes&fmt=csv&xmlsearch=Search' GObject.idle_add(self.download_csv, self.search_url)
def _create_activity(self): if self._handle.activity_id is None: self._handle.activity_id = create_activity_id() self._shell.NotifyLaunch( self._service_name, self._handle.activity_id, reply_handler=self._no_reply_handler, error_handler=self._notify_launch_error_handler) environ = get_environment(self._bundle) (log_path, log_file) = open_log_file(self._bundle) command = get_command(self._bundle, self._handle.activity_id, self._handle.object_id, self._handle.uri, self._handle.invited) dev_null = file('/dev/null', 'r') child = subprocess.Popen([str(s) for s in command], env=environ, cwd=str(self._bundle.get_path()), close_fds=True, stdin=dev_null.fileno(), stdout=log_file.fileno(), stderr=log_file.fileno()) GObject.child_watch_add(child.pid, _child_watch_cb, (log_file, self._handle.activity_id))
def run(self): GObject.timeout_add(100, self._idle, priority=GObject.PRIORITY_HIGH) while True: Gtk.main_iteration() gevent.sleep(.001)
def _import_gst(self): """Import the necessary GObject-related modules and assign `Gst` and `GObject` fields on this object. """ try: import gi except ImportError: raise FatalReplayGainError( "Failed to load GStreamer: python-gi not found" ) try: gi.require_version('Gst', '1.0') except ValueError as e: raise FatalReplayGainError( "Failed to load GStreamer 1.0: {0}".format(e) ) from gi.repository import GObject, Gst, GLib # Calling GObject.threads_init() is not needed for # PyGObject 3.10.2+ with warnings.catch_warnings(): warnings.simplefilter("ignore") GObject.threads_init() Gst.init([sys.argv[0]]) self.GObject = GObject self.GLib = GLib self.Gst = Gst
def checkFiles( self ): for monitored in self.monitoredFiles: if monitored.hasChanged(): if monitored.args: GObject.idle_add( monitored.callback, monitored.args ) else: GObject.idle_add( monitored.callback )
def __init__(self, window): Gtk.Dialog.__init__(self, _('Edit archive'), window, Gtk.DialogFlags.MODAL, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) self.kill = False # Dialog is killed. self.file_handler = window.file_handler self._window = window self._save_button = self.add_button(Gtk.STOCK_SAVE_AS, Gtk.ResponseType.OK) # There is no stock response for "import", but by using # RESPONSE_HELP we automatically get the button placed at the left. self._import_button = self.add_button(_('Import'), Gtk.ResponseType.HELP) self._import_button.set_image(Gtk.Image.new_from_stock(Gtk.STOCK_ADD, Gtk.IconSize.BUTTON)) self.set_border_width(4) self.resize(min(Gdk.Screen.get_default().get_width() - 50, 750), min(Gdk.Screen.get_default().get_height() - 50, 600)) self.connect('response', self._response) self._image_area = _ImageArea(self) self._other_area = _OtherArea(self) notebook = Gtk.Notebook() notebook.set_border_width(6) notebook.append_page(self._image_area, Gtk.Label(label=_('Images'))) notebook.append_page(self._other_area, Gtk.Label(label=_('Other files'))) self.vbox.pack_start(notebook, True, True, 0) self.show_all() GObject.idle_add(self._load_original_files)
def test_searchentry(self): from softwarecenter.ui.gtk3.widgets.searchentry import get_test_searchentry_window win = get_test_searchentry_window() s = "foo" win.entry.insert_text(s, len(s)) GObject.timeout_add(TIMEOUT, lambda: win.destroy()) Gtk.main()
def run(self, argv): GObject.threads_init() GObject.timeout_add(10, self.on_timer) self.connect("startup", self.on_startup) self.connect("activate", self.on_activate) self.connect("shutdown", self.on_shutdown) return super(Gtk3Example, self).run(argv)
def main(): debug = False print("Trackma-gtk v{}".format(utils.VERSION)) if '-h' in sys.argv: print("Usage: trackma-qt [options]") print() print('Options:') print(' -d Shows debugging information') print(' -h Shows this help') return if '-d' in sys.argv: debug = True app = TrackmaWindow(debug) try: GObject.threads_init() Gdk.threads_init() Gdk.threads_enter() app.main() Gtk.main() except utils.TrackmaFatal as e: md = Gtk.MessageDialog(None, Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, str(e)) md.run() md.destroy() finally: Gdk.threads_leave()
def __init__(self): GObject.GObject.__init__(self) self.connected = False # check is ONECONF_NET_CONNECTED is in the environment variables # if so force the network status to be connected or disconnected if "ONECONF_NET_CONNECTED" in os.environ: if os.environ["ONECONF_NET_CONNECTED"].lower() == 'true': GObject.idle_add(self._on_connection_state_changed, self.NM_STATE_CONNECTED_LOCAL) LOG.warn('forced netstate into connected mode...') else: GObject.idle_add(self._on_connection_state_changed, self.NM_STATE_DISCONNECTED) LOG.warn('forced netstate into disconnected mode...') return try: bus = dbus.SystemBus() nm = bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager') nm.connect_to_signal("StateChanged", self._on_connection_state_changed) network_state = nm.state(dbus_interface='org.freedesktop.NetworkManager') self._on_connection_state_changed(network_state) except Exception as e: LOG.warn("failed to init network state watcher '%s'" % e) self._on_connection_state_changed(self.NM_STATE_UNKNOWN)
def __init__(self, pipeline_string='videotestsrc pattern=18 ! tee name=t ! queue ! autovideosink t. ! queue ! videoconvert ! videorate ! video/x-raw,width=(int)320,height=(int)240,format=(string)RGB16,framerate=(fraction)30/1 ! appsink name=sink'): self.data = None# this will contain the data passed between self.source_id = None self.lock = Lock() self.isWhite = True self.isStream = True self.timestamp = 0 self.pipeline = Gst.parse_launch(pipeline_string) self.appsink = self.pipeline.get_by_name('sink') assert self.appsink, 'appsink element named \'sink\' not found' self.appsink.connect('new-sample', self.on_new_buffer) self.appsink.set_property('emit-signals', True) self.pipeline.set_state(Gst.State.PLAYING) # OUTPUT pipeline self.pipeline_out = Gst.parse_launch('appsrc name=source ! videoconvert ! autovideosink') self.appsrc = self.pipeline_out.get_by_name('source') assert self.appsrc, 'appsrc element named \'source\' not found' self.appsrc.set_property('caps', Gst.Caps.from_string('video/x-raw,format=(string)RGB16,width=(int)320,height=(int)240,framerate=(fraction)30/1')) self.appsrc.connect('need-data', self.on_need_data) self.appsrc.connect('enough-data', self.on_enough_data) self.pipeline_out.set_state(Gst.State.PLAYING) GObject.timeout_add_seconds(2, self._switch_data_type)
def run(): # Protobuf #c = ControllerProtobuf() # Directly connected to the vision server c = VisionManager() if not c.is_connected(): print("Vision server is not accessible.") return server = Server() server.start("127.0.0.1", 5030) # add observer output for "server" c.add_filter_output_observer(server.send) from gi.repository import Gtk, GObject import CapraVision.client.gtk.main GObject.threads_init() w = CapraVision.client.gtk.main.WinFilterChain(c) w.window.show_all() Gtk.main() # Close connection server.stop() c.close_server()
def __init__(self): #self.radio = tea5767() self.player = player() self.load = False self.defaullt = "/data/media/Music" self.config = configparser.ConfigParser() self.config.read('config.ini') interface = gtk.Builder() interface.add_from_file('./interface/interface.glade') self.volume = interface.get_object("volume") self.progression = interface.get_object("progression") self.music = interface.get_object("music") self.artiste = interface.get_object("artiste") self.cover = interface.get_object("pochette") self.mode = interface.get_object("mode") self.freq = interface.get_object("scale1") self.deroul = interface.get_object("liststore1") self.folder = interface.get_object("filechooserbutton1") self.tab = interface.get_object('notebook1') self.on_notebook1_switch_page(self.tab, None,self.tab.get_current_page()) self.fullScreen = interface.get_object("main") interface.connect_signals(self) gobject.idle_add(self.test) if True:#(self.config["player"]["last"] != self.defaullt) time.sleep(2) self.player.new_folder(self.defaullt) self.config["player"]["last"] = self.defaullt with open("./config.ini", 'w') as configfile: # save self.config.write(configfile)
def fullscreen(self): """ Makes the window fullscreen. """ if not self.is_fullscreen: GObject.idle_add(self.main.set_resizable, True) GObject.idle_add(self.main.fullscreen) self.is_fullscreen = True
def unfullscreen(self): """ Unfullscreens the window """ if self.is_fullscreen: GObject.idle_add(self.main.set_resizable, False) GObject.idle_add(self.main.unfullscreen) self.is_fullscreen = 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: GObject.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 go_to_bookmark(self, subfilenumber, identifier): if self._sub_file_number != subfilenumber: self.__load_file(subfilenumber, timeout=100) GObject.timeout_add(100, self.__scroll_to_bookmark_position_in_file, identifier)
def calculateDiffs(self, menuItem, showNotification=True): self.setMenuEnabled(False) self.packageTitle.set_label('Calculating file diffs...') while Gtk.events_pending(): Gtk.main_iteration() selected = self.getSelectedPackages() totalDiff = 0 for package in selected: diff = self.bkup.getFileSizeDiff(package) totalDiff += diff print(self.bkup.humanPrint(diff)) humanDiff = self.bkup.humanPrint(diff) newLabel = package + ' (' + humanDiff + ' change)' print(self.packages[package].set_label(newLabel)) self.setMenuEnabled(True) self.packageTitle.set_label('Packages from bkup.yaml:') self.removeDiffLabelTime = time.time() + 60 * 5 GObject.timeout_add(60 * 1000, self.checkDiffLabelRemovalTime) if showNotification: msg = Notify.Notification.new('Calculated file diffs', 'Bkup') msg.show() return totalDiff
#!/usr/bin/env python3 from gi.repository import Gtk, GObject def update_progressbar(): fraction = progressbar.get_fraction() if fraction < 1.0: progressbar.set_fraction(fraction + 0.1) else: progressbar.set_fraction(0.0) return True window = Gtk.Window() window.connect("destroy", lambda q: Gtk.main_quit()) progressbar = Gtk.ProgressBar() progressbar.set_show_text(True) window.add(progressbar) window.show_all() GObject.timeout_add(1000, update_progressbar) Gtk.main()
def on_my_value_changed(self, widget): if self._value_changed_timer: GObject.source_remove(self._value_changed_timer) self._value_changed_timer = GObject.timeout_add(300, self.update_settings_value)
def switchClipWin2(self): # self.newVideo.stopPlay() self.revealer2.set_reveal_child(False) self.revealer3.set_reveal_child(True) print("switchClipWin2") def on_key_press_event(self, widget, event): # print("Key press on widget: ", widget) # print(" Modifiers: ", event.state) # print(" Key val, name: ", event.keyval, Gdk.keyval_name(event.keyval)) # check the event modifiers (can also use SHIFTMASK, etc) ctrl = event.state & Gdk.ModifierType.CONTROL_MASK # see if we recognise a keypress if ctrl and event.keyval == Gdk.KEY_q: print("Quit App") Gtk.main_quit() GObject.threads_init() win = MyWindow() win.connect("destroy", Gtk.main_quit) # print(dir(win.button.props)) # win.set_size_request(800, 600) win.set_position(Gtk.WindowPosition.CENTER) # win.set_resizable(False) Gtk.main()
# Run the program # Gst.init(None) # Gst.debug_set_colored(Gst.DebugColorMode.ON) # Gst.debug_set_active(True) # Gst.debug_set_default_threshold(3) # player = VideoPlayer() # thread = threading.Thread(target=player.play) # thread.start() # GObject.threads_init() # evt_loop = GObject.MainLoop() # evt_loop.run() # GObject.threads_init() # Gst.init(None) # Gtk.main() # bu satır olmalı mı acaba? if __name__ == "__main__": uri = "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov" Gst.init(None) Gst.debug_set_colored(Gst.DebugColorMode.ON) Gst.debug_set_active(True) Gst.debug_set_default_threshold(2) player = VideoPlayer(uri, None) thread = threading.Thread(target=player.play) thread.start() GObject.threads_init() evt_loop = GObject.MainLoop() evt_loop.run()
def gobject_main_loop(): GObject.threads_init() self.main_loop = GObject.MainLoop() self.main_loop.run()
class ApiInfoPanel(GObject.Object, Gedit.WindowActivatable): __gtype_name__ = "ApiInfoPanel" window = GObject.property(type=Gedit.Window) def __init__(self, plugin): GObject.Object.__init__(self) self.plugin = plugin self.dataDir = plugin.plugin_info.get_data_dir() self.geditWindow = plugin.window self.builder = Gtk.Builder() self.builder.add_from_file(self.dataDir + "/" + "ui" + "/" + "ApiInfoWindow.glade") self.builder.connect_signals(self) self.scrolledWindow = self.builder.get_object("scrolledWindow") self.textView = self.builder.get_object("textView") self.textView.set_editable(False) self.textView.modify_fg(Gtk.StateType.NORMAL, Gdk.Color(red=65535, green=65535, blue=65535)) self.textView.modify_bg(Gtk.StateType.NORMAL, Gdk.Color(red=11776, green=13312, blue=13824)) self.textView.modify_bg(Gtk.StateType.SELECTED, Gdk.Color(red=51776, green=0, blue=0)) #self.textView.connect("button-press-event", self.onTextViewClick) if configuration.getShowApiInfoPanel(): self.geditBottomPanel = self.geditWindow.get_bottom_panel() self.geditBottomPanel.add_item( self.scrolledWindow, "haxe_api_info_panel", "api info", Gtk.Image.new_from_file(self.dataDir + "/" + "icons" + "/" + "haxe_logo_16.png") ) # Gtk.Image.new_from_stock(Gtk.STOCK_YES, Gtk.IconSize.MENU)) self.geditBottomPanel.activate_item(self.scrolledWindow) def activate(self): if configuration.getShowApiInfoPanel(): self.geditBottomPanel.activate_item(self.scrolledWindow) def remove(self): if configuration.getShowApiInfoPanel(): self.geditBottomPanel.remove_item(self.scrolledWindow) def setText(self, txt): textBuffer = self.textView.get_buffer() textBuffer.set_text(txt) def appendText(self, txt): textBuffer = self.textView.get_buffer() textBuffer.insert(textBuffer.get_end_iter(), txt) self.textView.scroll_mark_onscreen(textBuffer.get_insert()) #self.textView.scroll_to_mark(textBuffer.get_insert(), 0) def onTextViewClick(self, textView, event): if event.type == Gdk.EventType._2BUTTON_PRESS: hyperLink = self.parseHyperLinkLine() if hyperLink == None: return True return True def parseHyperLinkLine(self): doc = self.textView.get_buffer() iter = doc.get_iter_at_mark(doc.get_insert()) lineStart = iter.copy() lineEnd = iter.copy() lineStart.set_offset(iter.get_offset() - iter.get_line_offset()) #get the complete line lineEnd.forward_to_line_end() currentLine = unicode( doc.get_text(lineStart, lineEnd, include_hidden_chars=True)) if len(currentLine) == 0: return None #print currentLine; return None
def set_status(self, status, donedate=None, propagation=False, init=False): old_status = self.status self.can_be_deleted = False # No need to update children or whatever if the task is not loaded if status and self.is_loaded(): # we first modify the status of the children # If Done, we set the done date if status in [self.STA_DONE, self.STA_DISMISSED]: for c in self.get_subtasks(): if c.get_status() in [self.STA_ACTIVE]: c.set_status(status, donedate=donedate, propagation=True) # If the task is recurring, it must be duplicate with # another task id and the next occurence of the task # while preserving child/parent relations. # For a task to be duplicated, it must satisfy 3 rules. # 1- It is recurring. # 2- It has no parent or no recurring parent. # 3- It was directly marked as done (not by propagation from its parent). rules = [self.recurring, not propagation] if all(rules) and not self.is_parent_recurring(): # duplicate all the children nexttask_tid = self.duplicate_recursively() if self.has_parent(): for p_tid in self.get_parents(): par = self.req.get_task(p_tid) if (par.is_loaded() and par.get_status() in (self.STA_ACTIVE)): par.add_child(nexttask_tid) par.sync() # If we mark a task as Active and that some parent are not # Active, we break the parent/child relation # It has no sense to have an active subtask of a done parent. # (old_status check is necessary to avoid false positive a start) elif status in [self.STA_ACTIVE] and\ old_status in [self.STA_DONE, self.STA_DISMISSED]: if self.has_parent(): for p_tid in self.get_parents(): par = self.req.get_task(p_tid) if par.is_loaded() and par.get_status() in\ [self.STA_DONE, self.STA_DISMISSED]: # we can either break the parent/child relationship # self.remove_parent(p_tid) # or restore the parent too par.set_status(self.STA_ACTIVE) # We dont mark the children as Active because # They might be already completed after all # then the task itself if status: if not init: GObject.idle_add(self.req.emit, "status-changed", self.tid, status) self.status = status # Set closing date if status and status in [self.STA_DONE, self.STA_DISMISSED]: # to the specified date (if any) if donedate: self.closed_date = donedate # or to today else: self.closed_date = Date.today() self.sync()
class WindowActivatable(GObject.Object, Gedit.WindowActivatable): __gtype_name__ = "ExternalToolsWindowActivatable" window = GObject.property(type=Gedit.Window) def __init__(self): GObject.Object.__init__(self) self._manager = None self._manager_default_size = None self.menu = None def do_activate(self): # Ugly hack... we need to get access to the activatable to update the menuitems self.window._external_tools_window_activatable = self self._library = ToolLibrary() ui_manager = self.window.get_ui_manager() self._action_group = Gtk.ActionGroup(name='ExternalToolsPluginActions') self._action_group.set_translation_domain('gedit') self._action_group.add_actions([ ('ExternalToolManager', None, _('Manage _External Tools...'), None, _("Opens the External Tools Manager"), lambda action: self.open_dialog()), ('ExternalTools', None, _('External _Tools'), None, _("External tools"), None) ]) ui_manager.insert_action_group(self._action_group, -1) ui_string = """ <ui> <menubar name="MenuBar"> <menu name="ToolsMenu" action="Tools"> <placeholder name="ToolsOps_4"> <separator/> <menu name="ExternalToolsMenu" action="ExternalTools"> <placeholder name="ExternalToolPlaceholder"/> </menu> <separator/> </placeholder> <placeholder name="ToolsOps_5"> <menuitem name="ExternalToolManager" action="ExternalToolManager"/> </placeholder> </menu> </menubar> </ui>""" self._merge_id = ui_manager.add_ui_from_string(ui_string) # Create output console self._output_buffer = OutputPanel(self.plugin_info.get_data_dir(), self.window) self.menu = ToolMenu( self._library, self.window, self._output_buffer, "/MenuBar/ToolsMenu/ToolsOps_4/ExternalToolsMenu/ExternalToolPlaceholder" ) ui_manager.ensure_update() bottom = self.window.get_bottom_panel() image = Gtk.Image(stock=Gtk.STOCK_EXECUTE, icon_size=Gtk.IconSize.MENU) bottom.add_item(self._output_buffer.panel, "GeditExternalToolsShellOutput", _("Tool Output"), image) def do_update_state(self): if self.menu is not None: self.menu.filter(self.window.get_active_document()) self.window.get_ui_manager().ensure_update() def do_deactivate(self): self.window._external_tools_window_activatable = None ui_manager = self.window.get_ui_manager() self.menu.deactivate() ui_manager.remove_ui(self._merge_id) ui_manager.remove_action_group(self._action_group) ui_manager.ensure_update() bottom = self.window.get_bottom_panel() bottom.remove_item(self._output_buffer.panel) def open_dialog(self): if not self._manager: self._manager = Manager(self.plugin_info.get_data_dir()) if self._manager_default_size: self._manager.dialog.set_default_size( *self._manager_default_size) self._manager.dialog.connect('destroy', self.on_manager_destroy) self._manager.connect('tools-updated', self.on_manager_tools_updated) window = Gio.Application.get_default().get_active_window() self._manager.run(window) return self._manager.dialog def update_manager(self, tool): if self._manager: self._manager.tool_changed(tool, True) def on_manager_destroy(self, dialog): self._manager_default_size = self._manager.get_final_size() self._manager = None def on_manager_tools_updated(self, manager): for window in Gio.Application.get_default().get_windows(): window._external_tools_window_activatable.menu.update()
def onPlayStep(self): self.onFowardClick(None) if self.play: GObject.timeout_add(1000, self.onPlayStep)
energy[ver] -= 1 # The following will force the re-drawing of the graph, and issue a # re-drawing of the GTK window. win.graph.regenerate_surface(lazy=False) win.graph.queue_draw() # if doing an offscreen animation, dump frame to disk if offscreen: global count pixbuf = win.get_pixbuf() pixbuf.savev(r'./frames/sirs%06d.png' % count, 'png', [], []) if count > max_count: sys.exit(0) count += 1 # We need to return True so that the main loop will call this function more # than once. return True # Bind the function above as an 'idle' callback. cid = GObject.idle_add(update_state) # We will give the user the ability to stop the program by closing the window. win.connect("delete_event", Gtk.main_quit) # Actually show the window, and start the main loop. win.show_all() Gtk.main()
return self.emit('connection-removed', conn) def get_connections(self): return self._connections.values() def get_instance(): global _instance if _instance is None: _instance = ConnectionWatcher() return _instance if __name__ == '__main__': dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) def connection_added_cb(conn_watcher, conn): print 'new connection', conn.service_name def connection_removed_cb(conn_watcher, conn): print 'removed connection', conn.service_name watcher = ConnectionWatcher() watcher.connect('connection-added', connection_added_cb) watcher.connect('connection-removed', connection_removed_cb) loop = GObject.MainLoop() loop.run()
if icon_found: image.set_from_icon_name(realIconName, Gtk.IconSize.DND) image.set_pixel_size(iconSize) else: image = None return image except Exception, e: print "Exception " + e.__class__.__name__ + ": " + e.message return None def themeChanged( self, theme ): self.emit( "changed" ) GObject.type_register(IconManager) class easyButton( Gtk.Button ): def __init__( self, iconName, iconSize, labels = None, buttonWidth = -1, buttonHeight = -1 ): GObject.GObject.__init__( self ) self.connections = [ ] self.iconName = iconName self.iconSize = iconSize self.showIcon = True self.set_relief( Gtk.ReliefStyle.NONE ) self.set_size_request( buttonWidth, buttonHeight ) Align1 = Gtk.Alignment.new( 0, 0.5, 1.0, 0 ) HBox1 = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL )
def wrapper(*args, **kwargs): GObject.idle_add(func, *args, **kwargs)
def onPlayClick(self, event): self.play = True GObject.timeout_add(10, self.onPlayStep)
def _too_small_screen_exit(): global exit_timeout_id exit_timeout_id = GObject.timeout_add(200, _show_too_small_info) # Launch gtk+ main loop Gtk.main()
def run(self): GObject.threads_init() Gtk.main()
def stop_autosave(): global autosave_timeout_id if autosave_timeout_id == -1: return GObject.source_remove(autosave_timeout_id) autosave_timeout_id = -1
class Model(GObject.GObject, downloader.Handler): __gsignals__ = { 'download-pulse': (GObject.SIGNAL_RUN_FIRST, None, ()) } state = GObject.Property(type=str, default='start') prev_state = GObject.Property(type=str) mode = GObject.Property(type=str, default='audio') url = GObject.Property(type=str) error = GObject.Property(type=str) resolution = GObject.Property(type=GObject.TYPE_UINT, default=1080) download_dir = GObject.Property(type=str) download_dir_abs = GObject.Property(type=str) prefer_mpeg = GObject.Property(type=bool, default=False) download_playlist_index = GObject.Property(type=GObject.TYPE_INT64) download_playlist_count = GObject.Property(type=GObject.TYPE_INT64) download_filename = GObject.Property(type=str) download_title = GObject.Property(type=str) download_thumbnail = GObject.Property(type=str) # 0.0 - 1.0 (inclusive), negative if unknown: download_progress = GObject.Property(type=float, default=-1) download_bytes = GObject.Property(type=GObject.TYPE_INT64, default=-1) download_bytes_total = GObject.Property(type=GObject.TYPE_INT64, default=-1) download_speed = GObject.Property(type=GObject.TYPE_INT64, default=-1) download_eta = GObject.Property(type=GObject.TYPE_INT64, default=-1) resolutions = [ (MAX_RESOLUTION, N_('Best')), (4320, N_('4320p (8K)')), (2160, N_('2160p (4K)')), (1440, N_('1440p (HD)')), (1080, N_('1080p (HD)')), (720, N_('720p (HD)')), (480, N_('480p')), (360, N_('360p')), (240, N_('240p')), (144, N_('144p'))] def __init__(self, handler=None): super().__init__() self._handler = handler self._downloader = downloader.Downloader(self) self._download_finished_filenames = [] self._filemanager_proxy = Gio.DBusProxy.new_for_bus_sync( Gio.BusType.SESSION, Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES | Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS | Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION, None, 'org.freedesktop.FileManager1', '/org/freedesktop/FileManager1', 'org.freedesktop.FileManager1') bind_property(self, 'download-dir', self, 'download-dir-abs', expand_path) self.actions = Gio.SimpleActionGroup.new() self.actions.add_action_entries([ ('download', lambda *_: self.set_property('state', 'download')), ('cancel', lambda *_: self.set_property('state', 'cancel')), ('back', lambda *_: self.set_property('state', 'start')), ('open-download-dir', self._open_download_dir)]) bind_property(self, 'url', self.actions.lookup_action('download'), 'enabled', bool) bind_property(self, 'state', self, 'prev-state', self._state_transition) bind_property(self, 'state', self.actions.lookup_action('cancel'), 'enabled', lambda s: s == 'download') def _state_transition(self, state): if state == 'start': assert self.prev_state != 'download' elif state == 'download': assert self.prev_state == 'start' self.error = '' self.download_playlist_index = 0 self.download_playlist_count = 0 self.download_filename = '' self.download_title = '' self.download_thumbnail = '' self.download_progress = -1 self.download_bytes = -1 self.download_bytes_total = -1 self.download_speed = -1 self.download_eta = -1 self._download_finished_filenames.clear() self._downloader.start() elif state == 'cancel': assert self.prev_state == 'download' self._downloader.cancel() elif state in ['success', 'error']: assert self.prev_state == 'download' else: assert False return state def _open_download_dir(self, action, parameter, user_data): if len(self._download_finished_filenames) == 1: method = 'ShowItems' paths = [os.path.join(self.download_dir_abs, filename) for filename in self._download_finished_filenames] else: method = 'ShowFolders' paths = [self.download_dir_abs] parameters = GLib.Variant( '(ass)', ([Gio.File.new_for_path(p).get_uri() for p in paths], '')) try: self._filemanager_proxy.call_sync( method, parameters, Gio.DBusCallFlags.NONE, -1) except GLib.Error: g_log('youtube-dl', GLib.LogLevelFlags.LEVEL_WARNING, '%s', traceback.format_exc()) subprocess.run(['xdg-open', self.download_dir_abs], check=True) def on_pulse(self): assert self.state in ['download', 'cancel'] self.emit('download-pulse') def on_finished(self, success): assert self.state in ['download', 'cancel'] if self.state == 'cancel': self.state = 'start' else: self.state = 'success' if success else 'error' def get_download_dir(self): assert self.state in ['download', 'cancel'] return self.download_dir_abs def get_prefer_mpeg(self): assert self.state in ['download', 'cancel'] return self.prefer_mpeg def get_url(self): assert self.state in ['download', 'cancel'] return self.url def get_mode(self): assert self.state in ['download', 'cancel'] return self.mode def get_resolution(self): assert self.state in ['download', 'cancel'] return self.resolution def on_playlist_request(self): assert self.state in ['download', 'cancel'] return self._handler.on_playlist_request() def on_login_request(self): assert self.state in ['download', 'cancel'] return self._handler.on_login_request() def on_videopassword_request(self): assert self.state in ['download', 'cancel'] return self._handler.on_videopassword_request() def on_error(self, msg): assert self.state in ['download', 'cancel'] self.error = msg def on_load_progress(self, filename, progress, bytes_, bytes_total, eta, speed): assert self.state in ['download', 'cancel'] self.download_filename = filename self.download_progress = progress self.download_bytes = bytes_ self.download_bytes_total = bytes_total self.download_eta = eta self.download_speed = speed def on_progress_start(self, playlist_index, playlist_count, title, thumbnail): assert self.state in ['download', 'cancel'] self.download_playlist_index = playlist_index self.download_playlist_count = playlist_count self.download_title = title self.download_thumbnail = thumbnail def on_progress_end(self, filename): assert self.state in ['download', 'cancel'] self._download_finished_filenames.append(filename)
def open_assoc_file(): GObject.source_remove(assoc_timeout_id) projectaction.actually_load_project(assoc_file_path, block_recent_files=False)
def destroy_splash_screen(): splash_screen.destroy() GObject.source_remove(splash_timeout_id)
height = in_height - self._top - self._bottom new_format = othercaps.get_structure(0).copy() # https://lazka.github.io/pgi-docs/index.html#Gst-1.0/classes/Structure.html#Gst.Structure.fixate_field_nearest_int new_format.fixate_field_nearest_int("width", width) new_format.fixate_field_nearest_int("height", height) new_caps = Gst.Caps.new_empty() new_caps.append_structure(new_format) # https://lazka.github.io/pgi-docs/index.html#Gst-1.0/classes/Caps.html#Gst.Caps.fixate return new_caps.fixate() def do_set_caps(self, incaps: Gst.Caps, outcaps: Gst.Caps) -> bool: in_w, in_h = [incaps.get_structure(0).get_value(v) for v in ['width', 'height']] out_w, out_h = [outcaps.get_structure(0).get_value(v) for v in ['width', 'height']] # if input_size == output_size set plugin to passthrough mode # https://gstreamer.freedesktop.org/documentation/additional/design/element-transform.html?gi-language=c#processing if in_h == out_h and in_w == out_w: self.set_passthrough(True) return True # Register plugin to use it from command line GObject.type_register(GstVideoCrop) __gstelementfactory__ = (GstVideoCrop.GST_PLUGIN_NAME, Gst.Rank.NONE, GstVideoCrop)
def _do_window_resized_update(): GObject.source_remove(resize_timeout_id) updater.window_resized()
def activate(self): gobject.idle_add(self._do_activate)
def main(root_path): """ Called at application start. Initializes application with a default project. """ # DEBUG: Direct output to log file if log file set if _log_file != None: log_print_output_to_file() print "Application version: " + editorstate.appversion # Print OS, Python version and GTK+ version try: os_release_file = open("/etc/os-release", "r") os_text = os_release_file.read() s_index = os_text.find("PRETTY_NAME=") e_index = os_text.find("\n", s_index) print "OS: " + os_text[s_index + 13:e_index - 1] except: pass print "Python", sys.version gtk_version = "%s.%s.%s" % (Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version()) print "GTK+ version:", gtk_version editorstate.gtk_version = gtk_version try: editorstate.mlt_version = mlt.LIBMLT_VERSION except: editorstate.mlt_version = "0.0.99" # magic string for "not found" #print "SDL version:", str(editorstate.get_sdl_version()) # passing -xdg as a flag will change the user_dir location with XDG_CONFIG_HOME # For full xdg-app support all the launch processes need to add this too, currently not impl. for arg in sys.argv: if arg.lower() == "-xdg": editorstate.use_xdg = True # Create hidden folders if not present user_dir = utils.get_hidden_user_dir_path() print "User dir:", user_dir if not os.path.exists(user_dir): os.mkdir(user_dir) if not os.path.exists(user_dir + mltprofiles.USER_PROFILES_DIR): os.mkdir(user_dir + mltprofiles.USER_PROFILES_DIR) if not os.path.exists(user_dir + AUTOSAVE_DIR): os.mkdir(user_dir + AUTOSAVE_DIR) if not os.path.exists(user_dir + BATCH_DIR): os.mkdir(user_dir + BATCH_DIR) if not os.path.exists(user_dir + appconsts.AUDIO_LEVELS_DIR): os.mkdir(user_dir + appconsts.AUDIO_LEVELS_DIR) if not os.path.exists(utils.get_hidden_screenshot_dir_path()): os.mkdir(utils.get_hidden_screenshot_dir_path()) if not os.path.exists(user_dir + appconsts.GMIC_DIR): os.mkdir(user_dir + appconsts.GMIC_DIR) if not os.path.exists(user_dir + appconsts.MATCH_FRAME_DIR): os.mkdir(user_dir + appconsts.MATCH_FRAME_DIR) if not os.path.exists(user_dir + appconsts.TRIM_VIEW_DIR): os.mkdir(user_dir + appconsts.TRIM_VIEW_DIR) if not os.path.exists(user_dir + appconsts.NATRON_DIR): os.mkdir(user_dir + appconsts.NATRON_DIR) # Set paths. respaths.set_paths(root_path) # Load editor prefs and list of recent projects editorpersistance.load() if editorpersistance.prefs.theme != appconsts.LIGHT_THEME: respaths.apply_dark_theme() if editorpersistance.prefs.display_all_audio_levels == False: editorstate.display_all_audio_levels = False editorpersistance.create_thumbs_folder_if_needed(user_dir) editorpersistance.create_rendered_clips_folder_if_needed(user_dir) editorpersistance.save() # Init translations module with translations data translations.init_languages() translations.load_filters_translations() mlttransitions.init_module() # Apr-2017 - SvdB - Keyboard shortcuts shortcuts.load_shortcut_files() shortcuts.load_shortcuts() # We respaths and translations data available so we need to init in a function. workflow.init_data() # RHEL7/CentOS compatibility fix if gtk_version == "3.8.8": GObject.threads_init() # Init gtk threads Gdk.threads_init() Gdk.threads_enter() # Themes if editorpersistance.prefs.theme != appconsts.LIGHT_THEME: Gtk.Settings.get_default().set_property( "gtk-application-prefer-dark-theme", True) if editorpersistance.prefs.theme == appconsts.FLOWBLADE_THEME: gui.apply_gtk_css() # Load drag'n'drop images dnd.init() # Adjust gui parameters for smaller screens scr_w = Gdk.Screen.width() scr_h = Gdk.Screen.height() editorstate.SCREEN_WIDTH = scr_w editorstate.SCREEN_HEIGHT = scr_h print "Screen size:", scr_w, "x", scr_h print "Small height:", editorstate.screen_size_small_height() print "Small width:", editorstate.screen_size_small_width() _set_draw_params() # Refuse to run on too small screen. if scr_w < 1151 or scr_h < 767: _too_small_screen_exit() return # Splash screen if editorpersistance.prefs.display_splash_screen == True: show_splash_screen() # Init MLT framework repo = mlt.Factory().init() processutils.prepare_mlt_repo(repo) # Set numeric locale to use "." as radix, MLT initilizes this to OS locale and this causes bugs. locale.setlocale(locale.LC_NUMERIC, 'C') # Check for codecs and formats on the system. mltenv.check_available_features(repo) renderconsumer.load_render_profiles() # Load filter and compositor descriptions from xml files. mltfilters.load_filters_xml(mltenv.services) mlttransitions.load_compositors_xml(mltenv.transitions) # Replace some services if better replacements available. mltfilters.replace_services(mltenv.services) # Create list of available mlt profiles. mltprofiles.load_profile_list() # Save assoc file path if found in arguments. global assoc_file_path assoc_file_path = get_assoc_file_path() # There is always a project open, so at startup we create a default project. # Set default project as the project being edited. editorstate.project = projectdata.get_default_project() check_crash = True # Audiomonitoring being available needs to be known before GUI creation. audiomonitoring.init(editorstate.project.profile) # Set trim view mode to current default value. editorstate.show_trim_view = editorpersistance.prefs.trim_view_default # Check for tools and init tools integration. gmic.test_availablity() toolnatron.init() toolsintegration.init() #toolsintegration.test() # Create player object. create_player() # Create main window and set widget handles in gui.py for more convenient reference. create_gui() # Inits widgets with project data. init_project_gui() # Inits widgets with current sequence data. init_sequence_gui() # Launch player now that data and gui exist launch_player() # Editor and modules need some more initializing. init_editor_state() # Tracks need to be recentered if window is resized. # Connect listener for this now that the tline panel size allocation is sure to be available. global window_resize_id, window_state_id window_resize_id = gui.editor_window.window.connect( "size-allocate", lambda w, e: updater.window_resized()) window_state_id = gui.editor_window.window.connect( "window-state-event", lambda w, e: updater.window_resized()) # Get existing autosave files autosave_files = get_autosave_files() # Show splash if ((editorpersistance.prefs.display_splash_screen == True) and len(autosave_files) == 0 ) and not editorstate.runtime_version_greater_then_test_version( editorpersistance.prefs.workflow_dialog_last_version_shown, editorstate.appversion): global splash_timeout_id splash_timeout_id = GLib.timeout_add(2600, destroy_splash_screen) splash_screen.show_all() appconsts.SAVEFILE_VERSION = projectdata.SAVEFILE_VERSION # THIS IS A QUESTIONABLE IDEA TO SIMPLIFY IMPORTS, NOT DRY. WHEN DOING TOOLS THAT RUN IN ANOTHER PROCESSES AND SAVE PROJECTS, THIS LINE NEEDS TO BE THERE ALSO. # Every running instance has unique autosave file which is deleted at exit set_instance_autosave_id() # Existance of autosave file hints that program was exited abnormally. if check_crash == True and len(autosave_files) > 0: if len(autosave_files) == 1: GObject.timeout_add(10, autosave_recovery_dialog) else: GObject.timeout_add(10, autosaves_many_recovery_dialog) else: start_autosave() # We prefer to monkeypatch some callbacks into some modules, usually to # maintain a simpler and/or non-circular import structure. monkeypatch_callbacks() # File in assoc_file_path is opened after very short delay. if not (check_crash == True and len(autosave_files) > 0): if assoc_file_path != None: print "Launch assoc file:", assoc_file_path global assoc_timeout_id assoc_timeout_id = GObject.timeout_add(10, open_assoc_file) # SDL 2 consumer needs to created after Gtk.main() has run enough for window to be visble #if editorstate.get_sdl_version() == editorstate.SDL_2: # needs more state considerion still # print "SDL2 timeout launch" # global sdl2_timeout_id # sdl2_timeout_id = GObject.timeout_add(1500, create_sdl_2_consumer) # In PositionNumericalEntries we are using Gtk.Entry objects in a way that works for us nicely, but is somehow "error" for Gtk, so we just kill this. Gtk.Settings.get_default().set_property("gtk-error-bell", False) # Show first run worflow info dialog if not shown for this version of application. if editorstate.runtime_version_greater_then_test_version( editorpersistance.prefs.workflow_dialog_last_version_shown, editorstate.appversion): GObject.timeout_add(500, show_worflow_info_dialog) # Launch gtk+ main loop Gtk.main() Gdk.threads_leave()
def createSignal(signalName, emittingClass): GObject.signal_new(signalName, emittingClass, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, [])
class ActionGutter(Gtk.DrawingArea): __gtype_name__ = 'ActionGutter' action_mode = GObject.Property( type=int, nick='Action mode for chunk change actions', default=ActionMode.Replace, ) @GObject.Property( type=object, nick='List of diff chunks for display', ) def chunks(self): return self._chunks @chunks.setter def chunks_set(self, chunks): self._chunks = chunks self.chunk_starts = [c.start_a for c in chunks] @GObject.Property( type=Gtk.IconLookupFlags, nick='Which direction should directional changes appear to go', flags=( GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE | GObject.ParamFlags.CONSTRUCT_ONLY ), default=Gtk.IconLookupFlags.DIR_LTR, ) def icon_direction(self): return self._icon_direction @icon_direction.setter def icon_direction_set(self, direction: Gtk.IconLookupFlags): if direction not in ( Gtk.IconLookupFlags.DIR_LTR, Gtk.IconLookupFlags.DIR_RTL): raise ValueError('Invalid icon direction {}'.format(direction)) replace_icons = { Gtk.IconLookupFlags.DIR_LTR: 'apply-right', Gtk.IconLookupFlags.DIR_RTL: 'apply-left', } self.action_map = { ActionMode.Replace: ActionIcons.load(replace_icons[direction]), ActionMode.Delete: ActionIcons.load('delete'), ActionMode.Insert: ActionIcons.load('copy'), } self._icon_direction = direction _source_view: Gtk.TextView _source_editable_connect_id: int = 0 @GObject.Property( type=Gtk.TextView, nick='Text view for which action are displayed', default=None, ) def source_view(self): return self._source_view @source_view.setter def source_view_setter(self, view: Gtk.TextView): if self._source_editable_connect_id: self._source_view.disconnect(self._source_editable_connect_id) self._source_editable_connect_id = view.connect( 'notify::editable', lambda *args: self.queue_draw()) self._source_view = view self.queue_draw() _target_view: Gtk.TextView _target_editable_connect_id: int = 0 @GObject.Property( type=Gtk.TextView, nick='Text view to which actions are directed', default=None, ) def target_view(self): return self._target_view @target_view.setter def target_view_setter(self, view: Gtk.TextView): if self._target_editable_connect_id: self._target_view.disconnect(self._target_editable_connect_id) self._target_editable_connect_id = view.connect( 'notify::editable', lambda *args: self.queue_draw()) self._target_view = view self.queue_draw() @GObject.Signal def chunk_action_activated( self, action: str, # String-ified ChunkAction from_view: Gtk.TextView, to_view: Gtk.TextView, chunk: object, ) -> None: ... def __init__(self): super().__init__() # Object-type defaults self.chunks = [] self.action_map = {} # State for "button" implementation self.buttons = [] self.pointer_chunk = None self.pressed_chunk = None def on_setting_changed(self, settings, key): if key == 'style-scheme': self.fill_colors, self.line_colors = get_common_theme() alpha = self.fill_colors['current-chunk-highlight'].alpha self.chunk_highlights = { state: Gdk.RGBA(*[alpha + c * (1.0 - alpha) for c in colour]) for state, colour in self.fill_colors.items() } def do_realize(self): self.set_events( Gdk.EventMask.LEAVE_NOTIFY_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK ) self.connect('notify::action-mode', lambda *args: self.queue_draw()) meld_settings = get_meld_settings() meld_settings.connect('changed', self.on_setting_changed) self.on_setting_changed(meld_settings, 'style-scheme') return Gtk.DrawingArea.do_realize(self) def do_motion_notify_event(self, event): # This is the simplest button/intersection implementation in # the world, but it basically works for our purposes. for button in self.buttons: x1, y1, x2, y2, chunk = button # Check y first; it's more likely to be out of range if y1 <= event.y <= y2 and x1 <= event.x <= x2: new_pointer_chunk = chunk break else: new_pointer_chunk = None if new_pointer_chunk != self.pointer_chunk: self.pointer_chunk = new_pointer_chunk self.queue_draw() def do_leave_notify_event(self, event): if self.pointer_chunk: self.pointer_chunk = None self.queue_draw() def do_button_press_event(self, event): if self.pointer_chunk: self.pressed_chunk = self.pointer_chunk return Gtk.DrawingArea.do_button_press_event(self, event) def do_button_release_event(self, event): if self.pointer_chunk and self.pointer_chunk == self.pressed_chunk: self.activate(self.pressed_chunk) self.pressed_chunk = None return Gtk.DrawingArea.do_button_press_event(self, event) def _action_on_chunk(self, action: ChunkAction, chunk): self.chunk_action_activated.emit( action.value, self.source_view, self.target_view, chunk) def activate(self, chunk): action = self._classify_change_actions(chunk) # FIXME: When fully transitioned to GAction, we should see # whether we can do this by getting the container's action # group and activating the actions directly instead. if action == ActionMode.Replace: self._action_on_chunk(ChunkAction.replace, chunk) elif action == ActionMode.Delete: self._action_on_chunk(ChunkAction.delete, chunk) elif action == ActionMode.Insert: copy_menu = self._make_copy_menu(chunk) copy_menu.popup_at_pointer(None) def _make_copy_menu(self, chunk): copy_menu = Gtk.Menu() copy_up = Gtk.MenuItem.new_with_mnemonic(_('Copy _up')) copy_down = Gtk.MenuItem.new_with_mnemonic(_('Copy _down')) copy_menu.append(copy_up) copy_menu.append(copy_down) copy_menu.show_all() def copy_chunk(widget, action): self._action_on_chunk(action, chunk) copy_up.connect('activate', copy_chunk, ChunkAction.copy_up) copy_down.connect('activate', copy_chunk, ChunkAction.copy_down) return copy_menu def get_chunk_range(self, start_y, end_y): start_line = self.source_view.get_line_num_for_y(start_y) end_line = self.source_view.get_line_num_for_y(end_y) start_idx = bisect.bisect(self.chunk_starts, start_line) end_idx = bisect.bisect(self.chunk_starts, end_line) if start_idx > 0 and start_line <= self.chunks[start_idx - 1].end_a: start_idx -= 1 return self.chunks[start_idx:end_idx] def do_draw(self, context): view = self.source_view if not view or not view.get_realized(): return self.buttons = [] width = self.get_allocated_width() height = self.get_allocated_height() style_context = self.get_style_context() Gtk.render_background(style_context, context, 0, 0, width, height) buf = view.get_buffer() context.save() context.set_line_width(1.0) # Get our linked view's visible offset, get our vertical offset # against our view (e.g., for info bars at the top of the view) # and translate our context to match. view_y_start = view.get_visible_rect().y view_y_offset = view.translate_coordinates(self, 0, 0)[1] gutter_y_translate = view_y_offset - view_y_start context.translate(0, gutter_y_translate) button_x = 1 button_width = width - 2 for chunk in self.get_chunk_range(view_y_start, view_y_start + height): change_type, start_line, end_line, *_unused = chunk rect_y = view.get_y_for_line_num(start_line) rect_height = max( 0, view.get_y_for_line_num(end_line) - rect_y - 1) # Draw our rectangle outside x bounds, so we don't get # vertical lines. Fill first, over-fill with a highlight # if in the focused chunk, and then stroke the border. context.rectangle(-0.5, rect_y + 0.5, width + 1, rect_height) if start_line != end_line: context.set_source_rgba(*self.fill_colors[change_type]) context.fill_preserve() if view.current_chunk_check(chunk): highlight = self.fill_colors['current-chunk-highlight'] context.set_source_rgba(*highlight) context.fill_preserve() context.set_source_rgba(*self.line_colors[change_type]) context.stroke() # Button rendering and tracking action = self._classify_change_actions(chunk) if action is None: continue it = buf.get_iter_at_line(start_line) button_y, button_height = view.get_line_yrange(it) button_y += 1 button_height -= 2 button_style_context = get_style(None, 'button.flat.image-button') if chunk == self.pointer_chunk: button_style_context.set_state(Gtk.StateFlags.PRELIGHT) Gtk.render_background( button_style_context, context, button_x, button_y, button_width, button_height) Gtk.render_frame( button_style_context, context, button_x, button_y, button_width, button_height) # TODO: Ideally we'd do this in a pre-render step of some # kind, but I'm having trouble figuring out what that would # look like. self.buttons.append( ( button_x, button_y + gutter_y_translate, button_x + button_width, button_y + gutter_y_translate + button_height, chunk, ) ) pixbuf = self.action_map.get(action) icon_x = button_x + (button_width - pixbuf.props.width) // 2 icon_y = button_y + (button_height - pixbuf.props.height) // 2 Gtk.render_icon( button_style_context, context, pixbuf, icon_x, icon_y) context.restore() def _classify_change_actions(self, change) -> Optional[ActionMode]: """Classify possible actions for the given change Returns the action that can be performed given the content and context of the change. """ source_editable = self.source_view.get_editable() target_editable = self.target_view.get_editable() if not source_editable and not target_editable: return None # Reclassify conflict changes, since we treat them the same as a # normal two-way change as far as actions are concerned change_type = change[0] if change_type == 'conflict': if change[1] == change[2]: change_type = 'insert' elif change[3] == change[4]: change_type = 'delete' else: change_type = 'replace' if change_type == 'insert': return None action = self.action_mode if action == ActionMode.Delete and not source_editable: action = None elif action == ActionMode.Insert and change_type == 'delete': action = ActionMode.Replace if not target_editable: action = ActionMode.Delete return action
def set_Password(self, password): self.password = password if ((self.state == self.STATE_READY_FOR_SETUP) and self.SSID and self.password): GObject.timeout_add(1, self.connect)
class RadioToolButton(Gtk.RadioToolButton): """An implementation of a "push" button.""" __gtype_name__ = 'SugarRadioToolButton' def __init__(self, icon_name=None, **kwargs): self._accelerator = None self._tooltip = None self._xo_color = None self._hide_tooltip_on_click = True self._palette_invoker = ToolInvoker() GObject.GObject.__init__(self, **kwargs) self._palette_invoker.attach_tool(self) if icon_name: self.set_icon_name(icon_name) self.connect('destroy', self.__destroy_cb) def __destroy_cb(self, icon): if self._palette_invoker is not None: self._palette_invoker.detach() def set_tooltip(self, tooltip): if self.palette is None or self._tooltip is None: self.palette = Palette(tooltip) elif self.palette is not None: self.palette.set_primary_text(tooltip) self._tooltip = tooltip # Set label, shows up when toolbar overflows Gtk.RadioToolButton.set_label(self, tooltip) def get_tooltip(self): return self._tooltip tooltip = GObject.property(type=str, setter=set_tooltip, getter=get_tooltip) def set_accelerator(self, accelerator): self._accelerator = accelerator toolbutton.setup_accelerator(self) def get_accelerator(self): return self._accelerator accelerator = GObject.property(type=str, setter=set_accelerator, getter=get_accelerator) def set_icon_name(self, icon_name): icon = Icon(icon_name=icon_name, xo_color=self._xo_color) self.set_icon_widget(icon) icon.show() def get_icon_name(self): if self.props.icon_widget is not None: return self.props.icon_widget.props.icon_name else: return None icon_name = GObject.property(type=str, setter=set_icon_name, getter=get_icon_name) def set_xo_color(self, xo_color): if self._xo_color != xo_color: self._xo_color = xo_color if self.props.icon_widget is not None: self.props.icon_widget.props.xo_color = xo_color def get_xo_color(self): return self._xo_color xo_color = GObject.property(type=object, setter=set_xo_color, getter=get_xo_color) def create_palette(self): return None def get_palette(self): return self._palette_invoker.palette def set_palette(self, palette): self._palette_invoker.palette = palette palette = GObject.property(type=object, setter=set_palette, getter=get_palette) def get_palette_invoker(self): return self._palette_invoker def set_palette_invoker(self, palette_invoker): self._palette_invoker.detach() self._palette_invoker = palette_invoker palette_invoker = GObject.property(type=object, setter=set_palette_invoker, getter=get_palette_invoker) def do_draw(self, cr): if self.palette and self.palette.is_up(): allocation = self.get_allocation() # draw a black background, has been done by the engine before cr.set_source_rgb(0, 0, 0) cr.rectangle(0, 0, allocation.width, allocation.height) cr.paint() Gtk.RadioToolButton.do_draw(self, cr) if self.palette and self.palette.is_up(): invoker = self.palette.props.invoker invoker.draw_rectangle(cr, self.palette) return False def get_hide_tooltip_on_click(self): return self._hide_tooltip_on_click def set_hide_tooltip_on_click(self, hide_tooltip_on_click): if self._hide_tooltip_on_click != hide_tooltip_on_click: self._hide_tooltip_on_click = hide_tooltip_on_click hide_tooltip_on_click = GObject.property(type=bool, default=True, getter=get_hide_tooltip_on_click, setter=set_hide_tooltip_on_click) def do_clicked(self): if self._hide_tooltip_on_click and self.palette: self.palette.popdown(True)
def set_SSID(self, SSID): self.SSID = SSID if ((self.state == self.STATE_READY_FOR_SETUP) and self.SSID and self.password): GObject.timeout_add(1, self.connect)
class ControlYourTabsPlugin(GObject.Object, Gedit.WindowActivatable, PeasGtk.Configurable): __gtype_name__ = 'ControlYourTabsPlugin' window = GObject.property(type=Gedit.Window) SELECTED_TAB_COLUMN = 3 META_KEYS = [ 'Shift_L', 'Shift_R', 'Control_L', 'Control_R', 'Meta_L', 'Meta_R', 'Super_L', 'Super_R', 'Hyper_L', 'Hyper_R', 'Alt_L', 'Alt_R' ] # Compose, Apple? MAX_TAB_WINDOW_ROWS = 9 MAX_TAB_WINDOW_HEIGHT_PERCENTAGE = 0.5 # based on MAX_DOC_NAME_LENGTH in gedit-documents-panel.c MAX_DOC_NAME_LENGTH = 60 # based on formats in tab_get_name() in gedit-documents-panel.c < 3.12 TAB_NAME_GEDITPANEL_FORMATS = { 'modified': "<i>%s</i>", 'readonly': " [<i>%s</i>]" } # based on formats in document_row_sync_tab_name_and_icon() in gedit-documents-panel.c >= 3.12 TAB_NAME_LISTBOX_FORMATS = {'modified': "<b>%s</b>", 'readonly': " [%s]"} # based on switch statement in _gedit_tab_get_icon() in gedit-tab.c < 3.12 TAB_STATE_TO_STOCK_ICON = { Gedit.TabState.STATE_LOADING: Gtk.STOCK_OPEN, Gedit.TabState.STATE_REVERTING: Gtk.STOCK_REVERT_TO_SAVED, Gedit.TabState.STATE_SAVING: Gtk.STOCK_SAVE, Gedit.TabState.STATE_PRINTING: Gtk.STOCK_PRINT, Gedit.TabState.STATE_PRINT_PREVIEWING: Gtk.STOCK_PRINT_PREVIEW, Gedit.TabState.STATE_SHOWING_PRINT_PREVIEW: Gtk.STOCK_PRINT_PREVIEW, Gedit.TabState.STATE_LOADING_ERROR: Gtk.STOCK_DIALOG_ERROR, Gedit.TabState.STATE_REVERTING_ERROR: Gtk.STOCK_DIALOG_ERROR, Gedit.TabState.STATE_SAVING_ERROR: Gtk.STOCK_DIALOG_ERROR, Gedit.TabState.STATE_GENERIC_ERROR: Gtk.STOCK_DIALOG_ERROR, Gedit.TabState.STATE_EXTERNALLY_MODIFIED_NOTIFICATION: Gtk.STOCK_DIALOG_WARNING } # based on switch statement in _gedit_tab_get_icon() in gedit-tab.c >= 3.12 TAB_STATE_TO_NAMED_ICON = { Gedit.TabState.STATE_PRINTING: 'printer-printing-symbolic', Gedit.TabState.STATE_PRINT_PREVIEWING: 'printer-symbolic', Gedit.TabState.STATE_SHOWING_PRINT_PREVIEW: 'printer-symbolic', Gedit.TabState.STATE_LOADING_ERROR: 'dialog-error-symbolic', Gedit.TabState.STATE_REVERTING_ERROR: 'dialog-error-symbolic', Gedit.TabState.STATE_SAVING_ERROR: 'dialog-error-symbolic', Gedit.TabState.STATE_GENERIC_ERROR: 'dialog-error-symbolic', Gedit.TabState.STATE_EXTERNALLY_MODIFIED_NOTIFICATION: 'dialog-warning-symbolic' } SETTINGS_SCHEMA_ID = 'com.thingsthemselves.gedit.plugins.controlyourtabs' USE_TABBAR_ORDER = 'use-tabbar-order' # gedit plugin api def __init__(self): GObject.Object.__init__(self) def do_activate(self): window = self.window notebooks = {} tabwin = Gtk.Window(type=Gtk.WindowType.POPUP) tabwin.set_transient_for(window) tabwin.set_destroy_with_parent(True) tabwin.set_accept_focus(False) tabwin.set_decorated(False) tabwin.set_resizable(False) tabwin.set_position(Gtk.WindowPosition.CENTER_ON_PARENT) tabwin.set_type_hint(Gdk.WindowTypeHint.UTILITY) tabwin.set_skip_taskbar_hint(False) tabwin.set_skip_pager_hint(False) sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) sw.show() tabwin.add(sw) view = Gtk.TreeView() view.set_enable_search(False) view.set_headers_visible(False) view.show() sw.add(view) col = Gtk.TreeViewColumn(_("Documents")) col.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) icon_cell = Gtk.CellRendererPixbuf() name_cell = Gtk.CellRendererText() space_cell = Gtk.CellRendererPixbuf() col.pack_start(icon_cell, False) col.pack_start(name_cell, True) col.pack_start(space_cell, False) col.add_attribute(icon_cell, 'pixbuf', 0) col.add_attribute(name_cell, 'markup', 1) view.append_column(col) sel = view.get_selection() sel.set_mode(Gtk.SelectionMode.SINGLE) # hack to ensure tabwin is correctly positioned/sized on first show view.realize() try: GtkStack = Gtk.Stack except AttributeError: is_side_panel_stack = False else: is_side_panel_stack = isinstance(window.get_side_panel(), GtkStack) # since 3.12 self._tabbing = False self._paging = False self._switching = False self._ctrl_l = False self._ctrl_r = False self._multi = None self._notebooks = notebooks self._tabwin = tabwin self._view = view self._sw = sw self._icon_cell = icon_cell self._space_cell = space_cell self._tabwin_resize_id = None self._settings = self._get_settings() self._is_side_panel_stack = is_side_panel_stack tab = window.get_active_tab() if tab: self._setup(window, tab, notebooks, view) if self._multi: self.on_window_active_tab_changed(window, tab, notebooks, view) else: connect_handlers(self, window, ['tab-added'], 'window') def do_deactivate(self): window = self.window disconnect_handlers(self, window) if self._multi: disconnect_handlers(self, self._multi) notebooks = self._notebooks for notebook in notebooks: disconnect_handlers(self, notebooks[notebook][1]) for doc in window.get_documents(): disconnect_handlers(self, Gedit.Tab.get_from_document(doc)) self._cancel_tabwin_resize() self._end_switching() self._tabwin.destroy() self._tabbing = None self._paging = None self._switching = None self._ctrl_l = None self._ctrl_r = None self._multi = None self._notebooks = None self._tabwin = None self._view = None self._sw = None self._icon_cell = None self._space_cell = None self._tabwin_resize_id = None self._settings = None self._is_side_panel_stack = None def do_update_state(self): pass # settings ui def do_create_configure_widget(self): settings = self._get_settings() if settings: widget = Gtk.CheckButton( _("Use tabbar order for Ctrl+Tab / Ctrl+Shift+Tab")) widget.set_active(settings.get_boolean(self.USE_TABBAR_ORDER)) connect_handlers(self, widget, ['toggled'], 'configure_check_button', settings) connect_handlers(self, settings, ['changed::' + self.USE_TABBAR_ORDER], 'configure_settings', widget) else: widget = Gtk.Box() widget.add( Gtk.Label( _("Sorry, no preferences are available for this version of gedit." ))) widget.set_border_width(5) return widget def on_configure_check_button_toggled(self, widget, settings): settings.set_boolean(self.USE_TABBAR_ORDER, widget.get_active()) def on_configure_settings_changed_use_tabbar_order(self, settings, prop, widget): widget.set_active(settings.get_boolean(self.USE_TABBAR_ORDER)) # plugin setup def on_window_tab_added(self, window, tab): disconnect_handlers(self, window) self._setup(window, tab, self._notebooks, self._view) def _setup(self, window, tab, notebooks, view): if self._is_side_panel_stack: is_valid_size, icon_size_width, icon_size_height = Gtk.icon_size_lookup( Gtk.IconSize.MENU) else: is_valid_size, icon_size_width, icon_size_height = Gtk.icon_size_lookup_for_settings( tab.get_settings(), Gtk.IconSize.MENU) self._icon_cell.set_fixed_size(icon_size_height, icon_size_height) self._space_cell.set_fixed_size(icon_size_height, icon_size_height) multi = self._get_multi_notebook(tab) if multi: self._multi = multi for doc in window.get_documents(): self.on_multi_notebook_notebook_added( multi, Gedit.Tab.get_from_document(doc).get_parent(), notebooks, view) connect_handlers(self, multi, [ 'notebook-added', 'notebook-removed', 'tab-added', 'tab-removed' ], 'multi_notebook', notebooks, view) connect_handlers(self, window, [ 'tabs-reordered', 'active-tab-changed', 'key-press-event', 'key-release-event', 'focus-out-event', 'configure-event' ], 'window', notebooks, view) else: try: Gedit.debug_plugin_message( "cannot find multi notebook from %s", tab) except AttributeError: pass # signal handlers / main logic def on_multi_notebook_notebook_added(self, multi, notebook, notebooks, view): if notebook not in notebooks: model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, Gedit.Tab, 'gboolean') connect_handlers(self, model, ['row-inserted', 'row-deleted', 'row-changed'], 'model', view, view.get_selection()) notebooks[notebook] = ([], model) for tab in notebook.get_children(): self.on_multi_notebook_tab_added(multi, notebook, tab, notebooks, view) def on_multi_notebook_notebook_removed(self, multi, notebook, notebooks, view): if notebook in notebooks: for tab in notebook.get_children(): self.on_multi_notebook_tab_removed(multi, notebook, tab, notebooks, view) stack, model = notebooks[notebook] if view.get_model() is model: view.set_model(None) disconnect_handlers(self, model) del notebooks[notebook] def on_multi_notebook_tab_added(self, multi, notebook, tab, notebooks, view): stack, model = notebooks[notebook] if tab not in stack: stack.append(tab) model.append( (self._get_tab_icon(tab), self._get_tab_name(tab), tab, False)) connect_handlers(self, tab, ['notify::name', 'notify::state'], self.on_sync_icon_and_name, notebooks) def on_multi_notebook_tab_removed(self, multi, notebook, tab, notebooks, view): stack, model = notebooks[notebook] if tab in stack: disconnect_handlers(self, tab) model.remove(model.get_iter(stack.index(tab))) stack.remove(tab) def on_window_tabs_reordered(self, window, notebooks, view): multi = self._multi tab = window.get_active_tab() new_notebook = tab.get_parent() if tab not in notebooks[new_notebook][0]: old_notebook = None for notebook in notebooks: if tab in notebooks[notebook][0]: old_notebook = notebook break if old_notebook: self.on_multi_notebook_tab_removed(multi, old_notebook, tab, notebooks, view) self.on_multi_notebook_tab_added(multi, new_notebook, tab, notebooks, view) def on_window_active_tab_changed(self, window, tab, notebooks, view): if not self._switching: stack, model = notebooks[tab.get_parent()] if view.get_model() is not model: view.set_model(model) self._schedule_tabwin_resize() for row in model: row[self.SELECTED_TAB_COLUMN] = False if not self._tabbing and not self._paging: if tab in stack: model.move_after(model.get_iter(stack.index(tab)), None) stack.remove(tab) else: model.insert(0, (self._get_tab_icon(tab), self._get_tab_name(tab), tab, False)) stack.insert(0, tab) model[0][self.SELECTED_TAB_COLUMN] = True else: model[stack.index(tab)][self.SELECTED_TAB_COLUMN] = True def on_window_key_press_event(self, window, event, notebooks, view): key = Gdk.keyval_name(event.keyval) state = event.state & Gtk.accelerator_get_default_mod_mask() if key == 'Control_L': self._ctrl_l = True if key == 'Control_R': self._ctrl_r = True if key in self.META_KEYS or not state & Gdk.ModifierType.CONTROL_MASK: return False is_ctrl = state == Gdk.ModifierType.CONTROL_MASK is_ctrl_shift = state == Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK is_tab_key = key in ['ISO_Left_Tab', 'Tab'] is_page_key = key in ['Page_Up', 'Page_Down'] is_up_dir = key in ['ISO_Left_Tab', 'Page_Up'] if not (((is_ctrl or is_ctrl_shift) and is_tab_key) or (is_ctrl and is_page_key)): self._end_switching() return False cur = window.get_active_tab() if cur: settings = self._settings notebook = cur.get_parent() stack, model = notebooks[notebook] is_tabbing = is_tab_key and not (settings and settings.get_boolean( self.USE_TABBAR_ORDER)) tabs = stack if is_tabbing else notebook.get_children() tlen = len(tabs) if tlen > 1 and cur in tabs: i = -1 if is_up_dir else 1 next = tabs[(tabs.index(cur) + i) % tlen] model[stack.index(cur)][self.SELECTED_TAB_COLUMN] = False model[stack.index(next)][self.SELECTED_TAB_COLUMN] = True if is_tabbing: tabwin = self._tabwin if not self._tabbing: view.scroll_to_cell(Gtk.TreePath.new_first(), None, True, 0, 0) tabwin.show_all() else: tabwin.present_with_time(event.time) self._tabbing = True else: self._paging = True self._switching = True window.set_active_tab(next) self._switching = False return True def on_window_key_release_event(self, window, event, notebooks, view): key = Gdk.keyval_name(event.keyval) if key == 'Control_L': self._ctrl_l = False if key == 'Control_R': self._ctrl_r = False if not self._ctrl_l and not self._ctrl_r: self._end_switching() def on_window_focus_out_event(self, window, event, notebooks, view): self._end_switching() def on_window_configure_event(self, window, event, notebooks, view): self._schedule_tabwin_resize() def _end_switching(self): if self._tabbing or self._paging: self._tabbing = False self._paging = False self._switching = False self._ctrl_l = False self._ctrl_r = False self._tabwin.hide() window = self.window tab = window.get_active_tab() if tab: self.on_window_active_tab_changed(window, tab, self._notebooks, self._view) def on_model_row_inserted(self, model, path, iter, view, sel): if view.get_model() is model: self._schedule_tabwin_resize() def on_model_row_deleted(self, model, path, view, sel): if view.get_model() is model: self._schedule_tabwin_resize() def on_model_row_changed(self, model, path, iter, view, sel): if view.get_model() is model: if model[path][self.SELECTED_TAB_COLUMN]: sel.select_path(path) view.scroll_to_cell(path, None, True, 0.5, 0) else: sel.unselect_path(path) self._schedule_tabwin_resize() def on_sync_icon_and_name(self, tab, pspec, notebooks): stack, model = notebooks[tab.get_parent()] if tab in stack: path = stack.index(tab) model[path][0] = self._get_tab_icon(tab) model[path][1] = self._get_tab_name(tab) # tab name / icon # based on # < 3.12: tab_get_name() in gedit-documents-panel.c # >= 3.12: doc_get_name() and document_row_sync_tab_name_and_icon() in gedit-documents-panel.c def _get_tab_name(self, tab): doc = tab.get_document() name = doc.get_short_name_for_display() docname = Gedit.utils_str_middle_truncate(name, self.MAX_DOC_NAME_LENGTH) tab_name_formats = self.TAB_NAME_LISTBOX_FORMATS if self._is_side_panel_stack else self.TAB_NAME_GEDITPANEL_FORMATS if not doc.get_modified(): tab_name = escape(docname) else: tab_name = tab_name_formats['modified'] % escape(docname) try: file = doc.get_file() is_readonly = GtkSource.File.is_readonly(file) except AttributeError: is_readonly = doc.get_readonly() # deprecated since 3.18 if is_readonly: tab_name += tab_name_formats['readonly'] % escape(_("Read-Only")) return tab_name def _get_tab_icon(self, tab): if self._is_side_panel_stack: icon = self._get_named_tab_icon(tab) else: icon = self._get_stock_tab_icon(tab) return icon # based on _gedit_tab_get_icon() in gedit-tab.c >= 3.12 def _get_named_tab_icon(self, tab): icon_name = None pixbuf = None state = tab.get_state() if state in self.TAB_STATE_TO_NAMED_ICON: icon_name = self.TAB_STATE_TO_NAMED_ICON[state] if icon_name: theme = Gtk.IconTheme.get_for_screen(tab.get_screen()) is_valid_size, icon_size_width, icon_size_height = Gtk.icon_size_lookup( Gtk.IconSize.MENU) pixbuf = Gtk.IconTheme.load_icon(theme, icon_name, icon_size_height, 0) return pixbuf # based on _gedit_tab_get_icon() in gedit-tab.c < 3.12 def _get_stock_tab_icon(self, tab): theme = Gtk.IconTheme.get_for_screen(tab.get_screen()) is_valid_size, icon_size_width, icon_size_height = Gtk.icon_size_lookup_for_settings( tab.get_settings(), Gtk.IconSize.MENU) state = tab.get_state() if state in self.TAB_STATE_TO_STOCK_ICON: try: pixbuf = self._get_stock_icon( theme, self.TAB_STATE_TO_STOCK_ICON[state], icon_size_height) except GObject.GError: pixbuf = None else: pixbuf = None if not pixbuf: pixbuf = self._get_icon(theme, tab.get_document().get_location(), icon_size_height) return pixbuf # based on get_stock_icon() in gedit-tab.c in < 3.12 def _get_stock_icon(self, theme, stock, size): pixbuf = theme.load_icon(stock, size, 0) return self._resize_icon(pixbuf, size) # based on get_icon() in gedit-tab.c in < 3.12 def _get_icon(self, theme, location, size): if not location: return self._get_stock_icon(theme, Gtk.STOCK_FILE, size) # FIXME: Doing a sync stat is bad, this should be fixed try: info = location.query_info(Gio.FILE_ATTRIBUTE_STANDARD_ICON, Gio.FileQueryInfoFlags.NONE, None) except GObject.GError: info = None if not info: return self._get_stock_icon(theme, Gtk.STOCK_FILE, size) icon = info.get_icon() if not icon: return self._get_stock_icon(theme, Gtk.STOCK_FILE, size) icon_info = theme.lookup_by_gicon(icon, size, 0) if not icon_info: return self._get_stock_icon(theme, Gtk.STOCK_FILE, size) pixbuf = icon_info.load_icon() if not pixbuf: return self._get_stock_icon(theme, Gtk.STOCK_FILE, size) return self._resize_icon(pixbuf, size) # based on resize_icon() in gedit-tab.c in < 3.12 def _resize_icon(self, pixbuf, size): width = pixbuf.get_width() height = pixbuf.get_height() # if the icon is larger than the nominal size, scale down if max(width, height) > size: if width > height: height = height * size / width width = size else: width = width * size / height height = size pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR) return pixbuf # tab window resizing def _schedule_tabwin_resize(self): if not self._tabwin_resize_id: # need to wait a little before asking the treeview for its preferred size # maybe because treeview rendering is async? # this feels like a giant hack try: resize_id = GLib.idle_add(self._do_tabwin_resize) except TypeError: # gedit 3.0 resize_id = GObject.idle_add(self._do_tabwin_resize) self._tabwin_resize_id = resize_id def _cancel_tabwin_resize(self): if self._tabwin_resize_id: GLib.source_remove(self._tabwin_resize_id) self._tabwin_resize_id = None def _do_tabwin_resize(self): view = self._view sw = self._sw view_min_size, view_nat_size = view.get_preferred_size() view_height = max(view_min_size.height, view_nat_size.height) num_rows = max(len(view.get_model()), 2) row_height = math.ceil(view_height / num_rows) max_rows_height = self.MAX_TAB_WINDOW_ROWS * row_height win_width, win_height = self.window.get_size() max_win_height = round(self.MAX_TAB_WINDOW_HEIGHT_PERCENTAGE * win_height) max_height = min(max_rows_height, max_win_height) # we can't reliably tell if overlay scrolling is being used # since gtk_scrolled_window_get_overlay_scrolling() can still return True if GTK_OVERLAY_SCROLLING=0 is set # and even if we can tell if overlay scrolling is disabled, # we cannot tell if the scrolled window has reserved enough space for the scrollbar # fedora < 25: reserved # fedora >= 25: not reserved # ubuntu 17.04: reserved # so let's ignore overlay scrolling for now :-( vscrollbar_policy = Gtk.PolicyType.AUTOMATIC if view_height > max_height else Gtk.PolicyType.NEVER sw.set_policy(Gtk.PolicyType.NEVER, vscrollbar_policy) sw_min_size, sw_nat_size = sw.get_preferred_size() tabwin_width = max(sw_min_size.width, sw_nat_size.width) tabwin_height = min(view_height, max_height) self._tabwin.set_size_request(tabwin_width, tabwin_height) self._tabwin_resize_id = None return False # misc # this is a /hack/ def _get_multi_notebook(self, tab): multi = tab.get_parent() while multi: if multi.__gtype__.name == 'GeditMultiNotebook': break multi = multi.get_parent() return multi def _get_settings(self): schemas_path = os.path.join(BASE_PATH, 'schemas') try: # available in gedit >= 3.4 schema_source = Gio.SettingsSchemaSource.new_from_directory( schemas_path, Gio.SettingsSchemaSource.get_default(), False) schema = Gio.SettingsSchemaSource.lookup(schema_source, self.SETTINGS_SCHEMA_ID, False) settings = Gio.Settings.new_full(schema, None, None) if schema else None except AttributeError: settings = None except: try: Gedit.debug_plugin_message( "could not load settings schema from %s", schemas_path) except AttributeError: pass settings = None return settings