#!/usr/bin/python
import gi,os,socket,urllib.request,json,hashlib,getpass,threading,time,sys
from pathlib import Path
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk,Gdk,GLib,Pango
from bs4 import BeautifulSoup
from subprocess import Popen, PIPE
import fcntl
script = sys.argv[0]
if os.popen('ps aux | grep \"[%s]%s\"'% (script[:1], script[1:])).read().count(script) > 1: exit(0)
user = getpass.getuser()
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.set_icon_name("start-here")
self.set_border_width(10)
self.set_resizable(False)
self.set_position(Gtk.WindowPosition.CENTER)
self.headerbox = Gtk.VBox()
self.headerbar = Gtk.HeaderBar()
titlebar = Gtk.Label()
titlebar.set_markup('<b>Arch Updating Manager</b>')
self.headerbar.set_custom_title(titlebar)
self.set_titlebar(self.headerbar)
self.spinner = Gtk.Spinner()
def on_switch_activated(self, widget):
if switch1.get_active():
combobox.set_sensitive(True)
numbers.set_markup("<b>Old version number kept</b>")
else:
combobox.set_sensitive(False)
numbers.set_markup("")
def tooltip_info(self, widget):
if switch3.get_active():
ii = 0
for package in listbox.get_children():
package.set_has_tooltip(True)
package.set_tooltip_text(items_pacman_info[ii].rstrip())
ii += 1
ii = 0
for package_aur in listbox_aur.get_children():
package_aur.set_has_tooltip(True)
package_aur.set_tooltip_text(items_aur_info[ii].rstrip())
ii += 1
else:
for package in listbox.get_children():
package.set_has_tooltip(False)
package.set_tooltip_text('')
for package_aur in listbox_aur.get_children():
package_aur.set_has_tooltip(False)
package_aur.set_tooltip_text('')
def pkgbuild_infos_glib():
if self.swin2.get_child(): self.swin2.remove(self.swin2.get_child())
return False
def pkgbuild_info(self, widget):
GLib.idle_add(pkgbuild_infos_glib)
def apply_function(_):
if len(pacman_array) == 0 and len(aur_array) == 0 and switch1.get_active() == False and switch2.get_active() == False: return
def destroy_window(_):
apply_window.destroy()
def entry_text(_):
thread = threading.Thread(target=entry_text_thread)
thread.daemon = True
thread.start()
def show_command():
def unblock_fd(stream):
fd = stream.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
def buffer_update(stream, condition):
def destroy_window_refresh(_):
refresh_button.clicked()
apply_window.destroy()
a = stream.read()
buff.insert_at_cursor(a)
if a[-6:].rstrip() == 'ns **':
for id_ in IO_WATCH_ID:
GLib.source_remove(id_)
proc.terminate()
previous_button.set_always_show_image(True)
previous_button.set_label('back and refresh')
previous_button.set_sensitive(True)
close_button.set_sensitive(True)
previous_button.disconnect(previous_button_id)
previous_button.connect('clicked', destroy_window_refresh)
return False
else: return True
def bind_subprocess(proc):
global IO_WATCH_ID
unblock_fd(proc.stdout)
watch_id_stdout = GLib.io_add_watch(channel = proc.stdout, priority_ = GLib.IO_IN, condition = buffer_update)
unblock_fd(proc.stderr)
watch_id_stderr = GLib.io_add_watch(channel = proc.stderr, priority_ = GLib.IO_IN, condition = buffer_update)
IO_WATCH_ID = (watch_id_stdout, watch_id_stderr)
return IO_WATCH_ID
apply_window.set_default_size(1000,700)
previous_button.set_sensitive(False)
close_button.set_sensitive(False)
textview_scrollable = Gtk.ScrolledWindow()
textview_scrollable.set_border_width(10)
vbox_passwd.destroy()
label_password_check.destroy()
IO_WATCH_ID = tuple()
packages = ' '.join(pacman_array_sorted)
cmd = ''
try:
socket.create_connection(("www.google.com", 80))
if len(pacman_array) > 0: cmd = cmd + 'echo \"::PACMAN Updating::\" ; echo %s | sudo -Sk pacman -Syu --noconfirm %s ; echo \"::PACMAN Updating == > finished::\" ; echo ; '% (psswd,packages)
if len(aur_array) > 0:
bash_array = '('
for i in aur_array:
bash_array = bash_array + ' \"' + i + '\"'
bash_array = bash_array + ' )'
cmd = cmd + 'packs=%s ; echo \"::AUR Updating::\" ; for pack in \"${packs[@]}\" ; do echo \"cleaning up $pack directory, downloading snapshot tar.gz and extracting...\"; [[ -d \"/home/$USER/.cache/AUR/$pack\" ]] && rm -r /home/$USER/.cache/AUR/$pack ; wget -P /home/$USER/.cache/AUR https://aur.archlinux.org/cgit/aur.git/snapshot/$pack\'.tar.gz\' ; tar -xvzf /home/$USER/.cache/AUR/$pack\'.tar.gz\' -C /home/$USER/.cache/AUR ; echo \"done.\" ; cd /home/$USER/.cache/AUR/$pack ; echo \"makepkg PKGBUILD and updating $pack: \" ; makepkg -s ; pack_pkg=$(find /home/$USER/.cache/AUR/$pack -type f -name \"$pack*\" | grep \"pkg.tar.xz\") ; echo %s | sudo -Sk pacman -U $pack_pkg --noconfirm ; echo \"cleaning up directory.\" ; mv $pack_pkg /home/$USER/.cache/AUR ; rm -rf /home/$USER/.cache/AUR/$pack ; mkdir /home/$USER/.cache/AUR/$pack ; mv /home/$USER/.cache/AUR/*.pkg.tar.xz /home/$USER/.cache/AUR/*.tar.gz /home/$USER/.cache/AUR/$pack ; done ; echo \"::AUR Updating ==> finished::\" ; echo ; '% (bash_array,psswd)
if switch1.get_active(): cmd = cmd + 'echo \"::Removing Cache::\" ; echo %s | sudo -Sk paccache -rk%s --nocolor ; echo \"::Removing Cache ==> finished::\" ; echo ; '% (psswd,combobox.get_active())
if switch2.get_active(): cmd = cmd + 'echo \"::Removing Orphans::\" ; echo %s | sudo -Sk pacman -R $(pacman -Qdtq) ; echo \"::Removing Orphans ==> finished::\" ; echo ; '% psswd
cmd = cmd + 'echo ; echo \"** End Of Operations **\"'
except OSError:
cmd = 'echo internet connection failed!'
buff = Gtk.TextBuffer()
textview = Gtk.TextView.new_with_buffer(buff)
textview.set_editable(False)
fontdesc = Pango.FontDescription("monospace")
textview.modify_font(fontdesc)
textview_scrollable.add(textview)
apply_vbox.pack_start(textview_scrollable,True,True,10)
textview_scrollable.show_all()
proc = Popen("%s"% cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True, shell=True)
bind_subprocess(proc)
def gui_update_thread():
label_password_check.show()
password.set_sensitive(False)
def entry_text_thread():
GLib.idle_add(gui_update_thread)
global psswd
psswd = password.get_text()
if os.system('echo %s | sudo -Sk cat /etc/shadow'% psswd) == 256:
label_password_check.set_markup('<span color=\'red\'><b>password incorrect!</b></span>')
password.set_text('')
password.set_sensitive(True)
return
else:
GLib.idle_add(show_command)
def spinning_password(self, widget):
if password.get_sensitive(): spinner_password.stop()
else: spinner_password.start()
pacman_array_sorted = sorted(pacman_array, key=str.lower)
apply_window = Gtk.Window().new(Gtk.WindowType.TOPLEVEL)
apply_window.set_urgency_hint(True)
apply_window.set_decorated(False)
apply_window.set_modal(True)
apply_window.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
apply_window.set_transient_for(self)
apply_window.set_deletable(True)
apply_window.set_default_size(800,500)
apply_window.set_resizable(False)
apply_window.set_border_width(0)
apply_vbox = Gtk.VBox()
apply_headerbar = Gtk.HeaderBar()
previous_button = Gtk.Button.new_from_icon_name('go-previous', Gtk.IconSize.DIALOG)
previous_button_id = previous_button.connect('clicked', destroy_window)
close_button = Gtk.Button().new_with_label('Close app')
close_button.connect('clicked', Gtk.main_quit)
apply_headerbar.pack_start(previous_button)
apply_headerbar.pack_end(close_button)
apply_vbox.pack_start(apply_headerbar,False,False,0)
vbox_passwd = Gtk.VBox(homogeneous=False,spacing=15)
vbox_passwd.set_border_width(50)
apply_window.add(apply_vbox)
hbox_label = Gtk.HBox(homogeneous=False,spacing=10)
image_label = Gtk.Image.new_from_icon_name('dialog-password-symbolic', Gtk.IconSize.DIALOG)
label_passwd = Gtk.Label()
label_passwd.set_markup('\n\n<b>Authentication Required\n\nAuthentication is required to run Arch Updating Manager</b>\n')
hbox_label.pack_start(image_label,False,False,0)
hbox_label.pack_start(label_passwd,False,False,0)
vbox_passwd.pack_start(hbox_label,False,False,0)
hbox_password = Gtk.HBox(homogeneous=False,spacing=5)
hbox_password.set_border_width(50)
label_password = Gtk.Label()
label_password.set_markup('<b> Password: </b>')
password = Gtk.Entry()
password.set_visibility(False)
password.set_placeholder_text('root password here')
password.connect('activate', entry_text)
password.connect('state-changed', spinning_password)
label_password_check = Gtk.Label()
label_password_check.set_text('checking password')
spinner_password = Gtk.Spinner()
hbox_password.pack_start(label_password,False,False,0)
hbox_password.pack_start(spinner_password,False,False,0)
hbox_password.pack_start(password,True,True,0)
vbox_passwd.pack_start(hbox_password,False,False,0)
apply_vbox.pack_start(vbox_passwd,False,False,0)
apply_vbox.pack_start(label_password_check,False,False,40)
apply_window.show_all()
label_password_check.hide()
def exit_function(_):
Gtk.main_quit()
def change_mode():
if self.swin.get_child(): listbox.set_selection_mode(2)
if self.swin1.get_child(): listbox_aur.set_selection_mode(2)
return False
def on_changed_page(notebook, tab, index):
if index == 0:
if self.swin.get_child(): listbox.set_selection_mode(0)
if self.swin1.get_child(): listbox_aur.set_selection_mode(0)
GLib.idle_add(change_mode)
def show_listboxes():
self.swin.add(listbox)
listbox.show_all()
self.swin1.add(listbox_aur)
listbox_aur.show_all()
self.set_sensitive(True)
return False
def get_packages():
global listbox, listbox_aur, packs, items_pacman_info, items_aur_info, pacman_array, aur_array, pkgbuild_array, aur_array_info
listbox = Gtk.ListBox()
listbox.set_selection_mode(2)
listbox_aur = Gtk.ListBox()
listbox_aur.set_selection_mode(2)
pacman_array = []
aur_array = []
try:
socket.create_connection(("www.google.com", 80))
if apply_button.get_sensitive() != True: apply_button.set_sensitive(True)
packs = os.popen('checkupdates').read()
packs = packs.split("\n")
ii = 0
items_pacman_info = []
for i in packs[:-1]:
pacman_array.append(i.split(' ', 1)[0])
items_pacman = Gtk.MenuItem()
items_pacman.set_label(i.split(' ', 1)[0])
items_pacman_info.append([s for s in packs if i.split(' ', 1)[0] in s][0]+'\n'+os.popen('pacman -Si %s'% i.split(' ', 1)[0]).read())
items_pacman.set_tooltip_text([s for s in packs if i.split(' ', 1)[0] in s][0]+'\n'+os.popen('pacman -Si %s'% i.split(' ', 1)[0]).read().rstrip())
listbox.insert(items_pacman, ii)
if switch3.get_active(): items_pacman.set_has_tooltip(True)
else: items_pacman.set_has_tooltip(False)
ii += 1
frame1.set_label('PACMAN ({})'.format(ii))
listbox.connect('row-selected', pacman_show)
## get installable aur packages
ii = 0
pkgbuild_array = []
aur_array_info = []
items_aur_info = []
aur = os.popen('pacman -Qqm').read()
for i in range (0,(aur.count('\n'))):
with urllib.request.urlopen("https://aur.archlinux.org/rpc.php?v=5&type=info&arg=%s"% aur.split('\n', -1)[i]) as url:
data = json.loads(url.read().decode())
if data['resultcount'] != 0:
version_old = os.popen('pacman -Qi %s | grep \"Versione\" | awk \'{print$3}\''% aur.split('\n', -1)[i]).read()
if version_old.rstrip() != data['results'][0]['Version']:
version_new = data['results'][0]['Version']
filename = Path('/home/'+user+'/.cache/AUR/'+aur.split('\n', -1)[i]+'/'+aur.split('\n', -1)[i]+'.tar.gz')
if filename.exists(): hash_old = hashlib.md5(open(filename,'rb').read()).hexdigest() ; hash_new = os.popen('curl -s https://aur.archlinux.org/cgit/aur.git/snapshot/\"%s.tar.gz\" | md5sum | awk \'{print$1}\''% aur.split('\n', -1)[i]).read()
else: hash_old = ''
if hash_old != hash_new.rstrip() or hash_old == '':
aur_array.append(aur.split('\n', -1)[i])
aur_array_info.append(aur.split('\n', -1)[i])
items_aur = Gtk.MenuItem()
items_aur.set_label(aur.split('\n', -1)[i])
items_aur_info.append(os.popen('pacman -Qi %s'% aur.split('\n', -1)[i]).read())
items_aur.set_tooltip_text(os.popen('pacman -Qi %s'% aur.split('\n', -1)[i]).read().rstrip())
listbox_aur.insert(items_aur, ii)
url = "https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=%s"% aur.split('\n', -1)[i]
html = urllib.request.urlopen(url).read()
soup = BeautifulSoup(html, "lxml")
for script in soup(["script", "style"]):
script.extract()
text = soup.get_text()
lines = (line.strip() for line in text.splitlines())
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
text_pkgbuild = '\n'.join(chunk for chunk in chunks if chunk)
pkgbuild_array.append('# Maintainer:'+text_pkgbuild.split("# Maintainer:",1)[1])
if switch3.get_active(): items_aur.set_has_tooltip(True)
else: items_aur.set_has_tooltip(False)
ii += 1
frame2.set_label('AUR ({})'.format(ii))
listbox_aur.connect('row-selected', aur_show)
listbox_aur.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
listbox_aur.connect("motion-notify-event", on_pointer_motion)
except OSError:
items_pacman = Gtk.MenuItem()
items_pacman.set_label('no internet connection!')
listbox.insert(items_pacman, 0)
if apply_button.get_sensitive() == True: apply_button.set_sensitive(False)
frame1.set_label('PACMAN')
frame2.set_label('AUR')
frame3.set_label('')
items_aur = Gtk.MenuItem()
items_aur.set_label('no internet connection!')
listbox_aur.insert(items_aur, 0)
listbox.unselect_all()
listbox_aur.unselect_all()
GLib.idle_add(show_listboxes)
def refresh_function(_):
self.set_sensitive(False)
if self.swin.get_child(): self.swin.remove(self.swin.get_child())
if self.swin1.get_child(): self.swin1.remove(self.swin1.get_child())
if self.swin2.get_child(): self.swin2.remove(self.swin2.get_child())
frame1.set_label('PACMAN')
frame2.set_label('AUR')
frame3.set_label('')
thread = threading.Thread(target=get_packages)
thread.daemon = True
thread.start()
def pacman_show(self, widget):
if listbox.get_selected_row():
row = listbox.get_selected_row()
menuitem_label = row.get_child().get_label()
if row.get_opacity() == 1:
row.set_opacity(0.5)
pacman_array.remove(menuitem_label)
else:
row.set_opacity(1)
pacman_array.append(menuitem_label)
listbox.unselect_row(row)
return False
def aur_show(self, widget):
if listbox_aur.get_selected_row():
row = listbox_aur.get_selected_row()
auritem_label = row.get_child().get_label()
if row.get_opacity() == 1:
row.set_opacity(0.5)
aur_array.remove(auritem_label)
else:
row.set_opacity(1)
aur_array.append(auritem_label)
listbox_aur.unselect_row(row)
return False
def show_pkgbuild():
if self.swin2.get_child(): self.swin2.remove(self.swin2.get_child())
self.swin2.add(pkgbuild_label)
pkgbuild_label.show()
return False
def on_pointer_motion(self, widget):
global pkgbuild_label
if switch4.get_active() and aur_array:
row_y = listbox_aur.get_pointer()
pkgbuild_label = Gtk.Label()
index = aur_array_info.index(listbox_aur.get_row_at_y(row_y[1]).get_child().get_label())
pkgbuild_label.set_text(pkgbuild_array[index])
GLib.idle_add(show_pkgbuild)
def refresh_button_clicked():
GLib.source_remove(refresh_button_clicked_id)
refresh_button.clicked()
self.notebook = Gtk.Notebook()
self.add(self.notebook)
##################
# upgrading page #
##################
self.page1 = Gtk.VBox(homogeneous=False, spacing=10)
self.hbox1 = Gtk.HBox(homogeneous=True, spacing=10)
self.vbox_packages = Gtk.VBox(homogeneous=True, spacing=10)
self.page1.set_border_width(10)
frame1 = Gtk.Frame()
label_widget_pacman = Gtk.Label()
label_widget_pacman.set_markup('<b>PACMAN</b>')
frame1.set_label_widget(label_widget_pacman)
frame2 = Gtk.Frame()
label_widget_aur = Gtk.Label()
label_widget_aur.set_markup('<b>AUR</b>')
frame2.set_label_widget(label_widget_aur)
frame3 = Gtk.Frame()
frame3.set_label('')
apply_button = Gtk.Button()
apply_button.set_label(' Apply ')
apply_button.connect("clicked", apply_function)
exit_button = Gtk.Button()
exit_button.set_label(' Exit ')
exit_button.connect("clicked", exit_function)
refresh_button = Gtk.Button()
refresh_button.set_label(' Refresh ')
refresh_button.connect("clicked", refresh_function)
self.swin = Gtk.ScrolledWindow()
frame1.add(self.swin)
self.swin1 = Gtk.ScrolledWindow()
frame2.add(self.swin1)
self.swin2 = Gtk.ScrolledWindow()
frame3.add(self.swin2)
self.vbox_packages.pack_start(frame1, True, True, 0)
self.vbox_packages.pack_start(frame2, True, True, 0)
self.hbox1.pack_start(self.vbox_packages, True, True, 10)
self.hbox1.pack_start(frame3, True, True, 10)
self.page1.add(self.hbox1)
hbox5 = Gtk.HBox(homogeneous=False, spacing=10)
hbox5.pack_end(exit_button, False, False, 10)
hbox5.pack_end(apply_button, False, False, 0)
hbox5.pack_end(refresh_button, False, False, 0)
hbox5.pack_start(self.spinner, True, True, 0)
self.page1.pack_end(hbox5, False, False, 0)
image = Gtk.Image()
image.set_from_icon_name("system-software-install", Gtk.IconSize.DND)
image.set_tooltip_text(" update manager ")
self.notebook.append_page(self.page1, image)
################
# options page #
################
self.page2 = Gtk.VBox()
self.page2.set_border_width(10)
image = Gtk.Image()
image.set_from_icon_name("emblem-system", Gtk.IconSize.DND)
image.set_tooltip_text(" options ")
self.notebook.append_page(self.page2, image)
frame5 = Gtk.Frame()
frame5.set_label('OPTIONS')
vbox_options = Gtk.VBox(homogeneous=False,spacing=0)
hbox_cache = Gtk.HBox()
cache = Gtk.Label()
cache.set_markup("<b>Clear Cache</b>")
switch1 = Gtk.Switch()
switch1.connect("notify::active", on_switch_activated)
switch1.set_active(False)
vbox_options.pack_start(Gtk.Separator().new(0),False,False,10)
numbers = Gtk.Label()
numbers.set_markup("")
combobox = Gtk.ComboBoxText()
combobox.insert(0, "0", "0")
combobox.insert(1, "1", "1")
combobox.insert(2, "2", "2")
combobox.insert(3, "3", "3")
combobox.insert(4, "4", "4")
combobox.insert(5, "5", "5")
combobox.set_active(3)
combobox.set_sensitive(False)
hbox_cache.pack_start(cache, False, False, 10)
hbox_cache.pack_start(switch1, True, False, 10)
hbox_cache.pack_end(combobox, False, False, 10)
hbox_cache.pack_end(numbers, False, False, 10)
vbox_options.pack_start(hbox_cache, False, False, 10)
vbox_options.pack_start(Gtk.Separator().new(0),False,False,10)
hbox_orphans = Gtk.HBox(homogeneous=False, spacing=35)
orphans = Gtk.Label()
orphans.set_markup("<b>Remove Orphans</b>")
orphans.set_justify(Gtk.Justification.LEFT)
hbox_orphans.pack_start(orphans, False, False, 10)
switch2 = Gtk.Switch()
switch2.connect("notify::active", on_switch_activated)
switch2.set_active(False)
hbox_orphans.pack_end(switch2, False, False, 10)
vbox_options.pack_start(hbox_orphans, False, False, 10)
vbox_options.pack_start(Gtk.Separator().new(0),False,False,10)
hbox_tooltip = Gtk.HBox(homogeneous=False, spacing=35)
tooltip = Gtk.Label()
tooltip.set_markup("<b>Tooltip as Package Info</b>")
tooltip.set_justify(Gtk.Justification.LEFT)
hbox_tooltip.pack_start(tooltip, False, False, 10)
switch3 = Gtk.Switch()
switch3.connect("notify::active", tooltip_info)
switch3.set_active(False)
hbox_tooltip.pack_end(switch3, False, False, 10)
vbox_options.pack_start(hbox_tooltip, False, False, 10)
vbox_options.pack_start(Gtk.Separator().new(0),False,False,10)
hbox_pkgbuild = Gtk.HBox(homogeneous=False, spacing=35)
pkgbuild = Gtk.Label()
pkgbuild.set_markup("<b>Show new PKGBUILD</b>")
pkgbuild.set_justify(Gtk.Justification.LEFT)
hbox_pkgbuild.pack_start(pkgbuild, False, False, 10)
switch4 = Gtk.Switch()
switch4.connect("notify::active", pkgbuild_info)
switch4.set_active(False)
hbox_pkgbuild.pack_end(switch4, False, False, 10)
vbox_options.pack_start(hbox_pkgbuild, False, False, 10)
vbox_options.pack_start(Gtk.Separator().new(0),False,False,10)
frame5.add(vbox_options)
self.page2.pack_start(frame5, True, True, 0)
hbox_buttons = Gtk.HBox(homogeneous=False, spacing=0)
button_apply = Gtk.Button()
button_apply.set_label(' Apply ')
button_apply.connect("clicked", apply_function)
button_exit = Gtk.Button()
button_exit.set_label(' Exit ')
button_exit.connect("clicked", exit_function)
hbox_buttons.pack_end(button_exit, False, False, 0)
hbox_buttons.pack_end(button_apply, False, False, 10)
self.page2.pack_end(hbox_buttons, False, False, 15)
#############
# info page #
#############
self.page3 = Gtk.Box()
self.page3.set_border_width(10)
info = Gtk.Label()
info.set_markup('\n<b><big>UPDATING_ARCH_MANAGER</big></b>\n<i>version 1.0-2018</i>\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see <a href=\"http://www.gnu.org/licenses/\" title=\"open in browser: <i>http://www.gnu.org/licenses/</i>\"><i>this link</i></a>.\n')
info.set_justify(Gtk.Justification.CENTER)
self.page3.add(info)
image = Gtk.Image()
image.set_from_icon_name("help-about", Gtk.IconSize.DND)
image.set_tooltip_text(" info ")
self.notebook.append_page(self.page3, image)
def on_change_status_notebook(self, widget):
if self.get_sensitive(): self.spinner.stop()
else: self.spinner.start()
self.set_sensitive(False)
self.notebook.connect_after("switch-page", on_changed_page)
self.connect("state-changed", on_change_status_notebook)
refresh_button_clicked_id = GLib.idle_add(refresh_button_clicked)
##############
# end of gui #
##############
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()