269 lines
9.7 KiB
Python
Executable File
269 lines
9.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import dbus
|
|
import dbus.mainloop.glib
|
|
from gi.repository import AppIndicator3
|
|
from gi.repository import Gtk, GLib, GObject
|
|
import gi
|
|
import subprocess
|
|
import threading
|
|
import time
|
|
import sys
|
|
|
|
# Especificar las versiones antes de importar
|
|
gi.require_version('Gtk', '3.0')
|
|
gi.require_version('AppIndicator3', '0.1')
|
|
|
|
|
|
class NetworkMenu:
|
|
def __init__(self):
|
|
self.app = 'network-menu'
|
|
# Define el icono inicial
|
|
self.indicator = AppIndicator3.Indicator.new(
|
|
self.app,
|
|
"/home/teraflops/Icons/wifi_disconnected.png",
|
|
AppIndicator3.IndicatorCategory.SYSTEM_SERVICES
|
|
)
|
|
self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
|
|
|
|
self.menu = Gtk.Menu()
|
|
self.build_menu()
|
|
|
|
self.indicator.set_menu(self.menu)
|
|
|
|
# Inicializar D-Bus
|
|
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
|
self.bus = dbus.SystemBus()
|
|
|
|
try:
|
|
self.network_manager = self.bus.get_object(
|
|
'org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager')
|
|
self.network_manager_props = dbus.Interface(
|
|
self.network_manager, 'org.freedesktop.DBus.Properties')
|
|
except dbus.exceptions.DBusException as e:
|
|
print(
|
|
f"Error al conectar con NetworkManager a través de D-Bus: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Suscribirse a las señales de cambio de propiedades
|
|
self.bus.add_signal_receiver(
|
|
self.on_properties_changed,
|
|
dbus_interface='org.freedesktop.DBus.Properties',
|
|
signal_name='PropertiesChanged',
|
|
arg0='org.freedesktop.NetworkManager',
|
|
path='/org/freedesktop/NetworkManager',
|
|
)
|
|
|
|
# Obtener estado inicial
|
|
self.update_status_initial()
|
|
|
|
def build_menu(self):
|
|
# Botón Conectar WiFi
|
|
self.item_connect = Gtk.MenuItem(label='Conectar WiFi')
|
|
self.item_connect.connect('activate', self.connect_wifi)
|
|
self.menu.append(self.item_connect)
|
|
|
|
# Botón Desconectar WiFi
|
|
self.item_disconnect = Gtk.MenuItem(label='Desconectar WiFi')
|
|
self.item_disconnect.connect('activate', self.disconnect_wifi)
|
|
self.menu.append(self.item_disconnect)
|
|
|
|
# Botón Ver Redes Disponibles
|
|
self.item_view_networks = Gtk.MenuItem(label='Ver Redes Disponibles')
|
|
self.item_view_networks.connect('activate', self.show_network_list)
|
|
self.menu.append(self.item_view_networks)
|
|
|
|
# Separador
|
|
self.menu.append(Gtk.SeparatorMenuItem())
|
|
|
|
# Botón Salir
|
|
item_quit = Gtk.MenuItem(label='Salir')
|
|
item_quit.connect('activate', self.quit)
|
|
self.menu.append(item_quit)
|
|
|
|
self.menu.show_all()
|
|
|
|
def show_network_list(self, _):
|
|
# Llamar a la función para obtener la lista de redes
|
|
networks = self.get_available_networks_list()
|
|
# Crear la ventana de lista de redes
|
|
window = Gtk.Window(title="Redes Disponibles")
|
|
window.set_default_size(300, 200)
|
|
window.set_border_width(10)
|
|
|
|
# Crear una caja vertical para la lista de redes y el botón de cerrar
|
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
|
|
|
|
# Añadir botones para cada red disponible
|
|
for network in networks:
|
|
button = Gtk.Button(label=network)
|
|
button.connect(
|
|
"clicked", self.prompt_password_and_connect, network)
|
|
vbox.pack_start(button, True, True, 0)
|
|
|
|
# Añadir un botón para cerrar la ventana
|
|
close_button = Gtk.Button(label="Cerrar")
|
|
close_button.connect("clicked", lambda x: window.destroy())
|
|
vbox.pack_start(close_button, False, False, 0)
|
|
|
|
window.add(vbox)
|
|
window.show_all()
|
|
|
|
def prompt_password_and_connect(self, button, network):
|
|
# Crear un diálogo para solicitar la contraseña
|
|
dialog = Gtk.Dialog(
|
|
title=f"Conectar a {network}",
|
|
transient_for=button.get_toplevel(),
|
|
flags=0
|
|
)
|
|
dialog.add_buttons(
|
|
Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
|
|
Gtk.STOCK_OK, Gtk.ResponseType.OK
|
|
)
|
|
|
|
# Crear un campo de entrada de texto para la contraseña
|
|
box = dialog.get_content_area()
|
|
label = Gtk.Label(label="Introduce la contraseña:")
|
|
box.add(label)
|
|
|
|
password_entry = Gtk.Entry()
|
|
# Ocultar la contraseña al escribir
|
|
password_entry.set_visibility(False)
|
|
box.add(password_entry)
|
|
dialog.show_all()
|
|
|
|
# Ejecutar el diálogo y obtener la respuesta del usuario
|
|
response = dialog.run()
|
|
if response == Gtk.ResponseType.OK:
|
|
password = password_entry.get_text()
|
|
print(f"Intentando conectar a la red: {
|
|
network} con la contraseña ingresada.")
|
|
# Llamar a nmcli con la contraseña
|
|
subprocess.run(['nmcli', 'device', 'wifi',
|
|
'connect', network, 'password', password])
|
|
self.show_notification(f"Intentando conectar a {network}")
|
|
else:
|
|
print("Conexión cancelada por el usuario.")
|
|
|
|
dialog.destroy()
|
|
|
|
def quit(self, _):
|
|
Gtk.main_quit()
|
|
|
|
def connect_wifi(self, _):
|
|
ssid = self.get_available_ssid()
|
|
if ssid:
|
|
print(f"Conectando a {ssid}")
|
|
subprocess.run(['nmcli', 'device', 'wifi', 'connect', ssid])
|
|
self.show_notification(f"Conectando a {ssid}...")
|
|
else:
|
|
print("No se encontraron redes WiFi disponibles.")
|
|
self.show_notification("No se encontraron redes WiFi disponibles.")
|
|
|
|
def disconnect_wifi(self, _):
|
|
print("Desconectando WiFi...")
|
|
subprocess.run(['nmcli', 'radio', 'wifi', 'off'])
|
|
self.show_notification("WiFi Desconectado.")
|
|
|
|
def get_available_ssid(self):
|
|
try:
|
|
output = subprocess.getoutput(
|
|
'nmcli -t -f SSID,SECURITY dev wifi list')
|
|
print(f"Redes WiFi disponibles:\n{output}")
|
|
networks = [line.split(':')[0]
|
|
for line in output.split('\n') if line]
|
|
networks = list(dict.fromkeys(filter(None, networks)))
|
|
print(f"SSIDs filtrados: {networks}")
|
|
if networks:
|
|
return networks[0]
|
|
return None
|
|
except Exception as e:
|
|
print(f"Error al obtener SSID disponibles: {e}", file=sys.stderr)
|
|
return None
|
|
|
|
def get_available_networks_list(self):
|
|
try:
|
|
output = subprocess.getoutput(
|
|
'nmcli -t -f SSID,SECURITY dev wifi list')
|
|
networks = [line.split(':')[0]
|
|
for line in output.split('\n') if line]
|
|
return list(dict.fromkeys(filter(None, networks)))
|
|
except Exception as e:
|
|
print(f"Error al obtener la lista de redes disponibles: {
|
|
e}", file=sys.stderr)
|
|
return ["Error al obtener redes"]
|
|
|
|
def show_notification(self, message):
|
|
subprocess.run(['notify-send', message])
|
|
|
|
def update_status_initial(self):
|
|
try:
|
|
wifi_state = self.get_wifi_state()
|
|
ssid = self.get_connected_ssid()
|
|
self.set_indicator(wifi_state, ssid)
|
|
except dbus.exceptions.DBusException as e:
|
|
print(f"Error al obtener el estado inicial: {e}", file=sys.stderr)
|
|
|
|
def on_properties_changed(self, interface, changed_properties, invalidated_properties):
|
|
if 'State' in changed_properties:
|
|
wifi_state = self.get_wifi_state()
|
|
ssid = self.get_connected_ssid()
|
|
self.set_indicator(wifi_state, ssid)
|
|
|
|
def set_indicator(self, wifi_state, ssid):
|
|
if wifi_state == 'disabled':
|
|
icon = "/home/teraflops/Icons/wifi_disabled.png"
|
|
tooltip = "WiFi Apagado"
|
|
elif wifi_state == 'enabled' and not ssid:
|
|
icon = "/home/teraflops/Icons/wifi_disconnected.png"
|
|
tooltip = "WiFi Encendido (No Conectado)"
|
|
elif wifi_state == 'enabled' and ssid:
|
|
icon = "/home/teraflops/Icons/wifi_enabled.png"
|
|
tooltip = f"Conectado a: {ssid}"
|
|
else:
|
|
icon = "/home/teraflops/Icons/wifi_unknown.png"
|
|
tooltip = "WiFi Estado Desconocido"
|
|
|
|
print(f"Actualizando indicador: Icono={icon}, Tooltip='{tooltip}'")
|
|
self.indicator.set_icon_full(icon, tooltip)
|
|
self.indicator.set_title(tooltip)
|
|
self.indicator.set_secondary_activate_target(None)
|
|
|
|
def get_wifi_state(self):
|
|
try:
|
|
output = subprocess.getoutput("nmcli radio wifi")
|
|
print(f"Estado WiFi: {output}")
|
|
return output.lower()
|
|
except Exception as e:
|
|
print(f"Error al obtener el estado de WiFi: {e}", file=sys.stderr)
|
|
return "unknown"
|
|
|
|
def get_connected_ssid(self):
|
|
try:
|
|
# Usar iwgetid para obtener el SSID conectado
|
|
ssid = subprocess.getoutput("iwgetid -r").strip()
|
|
if ssid:
|
|
print(f"SSID conectado obtenido con iwgetid: {ssid}")
|
|
return ssid
|
|
else:
|
|
# Fallback a nmcli si iwgetid no retorna SSID
|
|
output = subprocess.getoutput(
|
|
"nmcli -t -f ACTIVE,SSID dev wifi | grep '^yes' | cut -d':' -f2").strip()
|
|
if output:
|
|
print(f"SSID conectado obtenido con nmcli: {output}")
|
|
return output
|
|
else:
|
|
print(f"SSID conectado obtenido: None")
|
|
return None
|
|
except Exception as e:
|
|
print(f"Error al obtener SSID conectado: {e}", file=sys.stderr)
|
|
return None
|
|
|
|
|
|
def main():
|
|
NetworkMenu()
|
|
Gtk.main()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|