Now About Social Code
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2024-10-06 17:34:29 +0100
committerLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2024-10-06 17:34:29 +0100
commitdb10dc4fdd656b25442c63eb02ea30931eee300e (patch)
tree9b2a4e835d6d52b48c0e7fb9bcb83884999ee1da
parent0dc8409b168b293e9566dc5a35bded510fbd043d (diff)
window: Add interface for connecting and disconnecting
-rw-r--r--src/chat.py3
-rw-r--r--src/config.py18
-rw-r--r--src/gtk/preferences.ui12
-rw-r--r--src/gtk/welcome.ui38
-rw-r--r--src/main.py51
-rw-r--r--src/meson.build1
-rw-r--r--src/preferences.py3
-rw-r--r--src/relay/network.py36
-rw-r--r--src/weegtk.gresource.xml1
-rw-r--r--src/welcome.py38
-rw-r--r--src/window.py12
-rw-r--r--src/window.ui6
12 files changed, 187 insertions, 32 deletions
diff --git a/src/chat.py b/src/chat.py
index 603c2be..b82b4a3 100644
--- a/src/chat.py
+++ b/src/chat.py
@@ -1,4 +1,4 @@
-# window.py
+# chat.py
#
# Copyright 2024 Lucas Fryzek
#
@@ -179,3 +179,4 @@ class WeegtkChat(Adw.Bin):
dialog = Gtk.FileDialog()
dialog.set_title("Select file to upload")
dialog.open(self.get_root(), None, self.open_file_dialog, self)
+
diff --git a/src/config.py b/src/config.py
index ac52063..dc7d507 100644
--- a/src/config.py
+++ b/src/config.py
@@ -34,13 +34,13 @@ CONFIG_DEFAULT_RELAY_LINES = 50
CONFIG_DEFAULT_SECTIONS = ('relay', 'look', 'color', 'ssh', 'upload')
CONFIG_DEFAULT_OPTIONS = (('relay.hostname', ''),
- ('relay.port', ''),
- ('relay.ssl', 'off'),
+ ('relay.port', 0),
+ ('relay.ssl', False),
('relay.password', ''),
- ('relay.autoconnect', 'off'),
+ ('relay.autoconnect', False),
('relay.lines', str(CONFIG_DEFAULT_RELAY_LINES)),
('ssh.host', ''),
- ('ssh.port', ''),
+ ('ssh.port', 0),
('ssh.username', ''),
('ssh.key', ''),
('upload.url', ''),
@@ -139,3 +139,13 @@ def color_options():
"""Return color options."""
global config_options
return config_options["color"]
+
+def str_to_bool(value):
+ truthy = ["true", "1", "on", "y", "yes", "t", "i"]
+ #falsy = ["false", "0", "off", "n", "no", "f", "o"]
+
+ lower_val = value.lower()
+ if lower_val in truthy:
+ return True
+ else:
+ return False
diff --git a/src/gtk/preferences.ui b/src/gtk/preferences.ui
index 9e4d9fc..77f3c14 100644
--- a/src/gtk/preferences.ui
+++ b/src/gtk/preferences.ui
@@ -13,7 +13,12 @@
<property name="use-underline">True</property>
<child>
<object class="AdwPreferencesGroup">
- <property name="title" translatable="yes">Connection</property>
+ <property name="title" translatable="yes">Relay Connection</property>
+ <child>
+ <object class="AdwSwitchRow" id="autoconnect">
+ <property name="title" translatable="yes">Autoconnect</property>
+ </object>
+ </child>
<child>
<object class="AdwEntryRow" id="hostname">
<property name="title" translatable="yes">Hostname</property>
@@ -31,6 +36,11 @@
<property name="title" translatable="yes">Password</property>
</object>
</child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwPreferencesGroup">
+ <property name="title" translatable="yes">SSH Connection</property>
<child>
<object class="AdwEntryRow" id="ssh_host">
<property name="title" translatable="yes">SSH host</property>
diff --git a/src/gtk/welcome.ui b/src/gtk/welcome.ui
new file mode 100644
index 0000000..9b6ad76
--- /dev/null
+++ b/src/gtk/welcome.ui
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk" version="4.0"/>
+ <requires lib="libadwaita" version="1.0"/>
+ <template class="WeegtkWelcome" parent="AdwBin">
+ <property name="child">
+ <object class="AdwToolbarView">
+ <child type="top">
+ <object class="AdwHeaderBar">
+ <property name="show-title">False</property>
+ </object>
+ </child>
+ <property name="content">
+ <object class="AdwStatusPage">
+ <property name="icon-name">com.fryzekconcepts.weegtk-symbolic</property>
+ <property name="title" translatable="yes">Welcome to Weegtk</property>
+ <property name="description" translatable="yes">Change connection settings in preferences</property>
+ <property name="child">
+ <object class="GtkButton">
+ <signal name="clicked" handler="connect_network"/>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ <property name="child">
+ <object class="AdwButtonContent">
+ <property name="icon-name">network-wired-symbolic</property>
+ <property name="label" translatable="yes">_Connect</property>
+ <property name="use-underline">True</property>
+ </object>
+ </property>
+ </object>
+ </property>
+ </object>
+ </property>
+ </object>
+ </property>
+ </template>
+</interface>
diff --git a/src/main.py b/src/main.py
index 5a1427a..53206be 100644
--- a/src/main.py
+++ b/src/main.py
@@ -27,11 +27,12 @@ gi.require_version('Adw', '1')
from gi.repository import Gtk, Gio, Adw
from .window import WeegtkWindow
-from .network import Network
+from weegtk import network
from weegtk import protocol
from weegtk import config
from .chat import WeegtkChat
from .preferences import WeegtkPreferences
+from .welcome import WeegtkWelcome
class WeegtkApplication(Adw.Application):
"""The main application singleton class."""
@@ -42,13 +43,20 @@ class WeegtkApplication(Adw.Application):
self.create_action('quit', lambda *_: self.quit(), ['<primary>q'])
self.create_action('about', self.on_about_action)
self.create_action('preferences', self.on_preferences_action)
+ self.create_action('disconnect', self.disconnect)
- self.network = Network()
+ self.network = network.Network()
self.network.connect("status_changed", self._network_status_changed)
self.network.connect("message_from_weechat", self._network_weechat_msg)
+ self.buffers = []
+
+ conf = config.read()
+ if config.str_to_bool(conf["relay"]["autoconnect"]):
+ self.connect_to_weechat()
+
+ def connect_to_weechat(self, *args):
conf = config.read()
- #self.network.connect_weechat("localhost", "9001", False, relay_pw, None, "")
self.network.connect_weechat_ssh(conf["ssh"]["host"],
conf["ssh"]["port"],
conf["ssh"]["username"],
@@ -56,21 +64,25 @@ class WeegtkApplication(Adw.Application):
conf["relay"]["hostname"],
conf["relay"]["port"],
conf["relay"]["password"])
-
+ def clear_buffers(self):
+ for buffer in self.buffers:
+ self.props.active_window.stack.remove(buffer)
self.buffers = []
+ def disconnect(self, *args):
+ self.network.disconnect_weechat()
+
+ def handle_disconnect(self):
+ self.props.active_window.set_page(self.welcome_page)
+ self.clear_buffers()
+
def _network_status_changed(self, source_object, status, extra):
"""Called when the network status has changed."""
- # TODO handle this
- #if self.config.getboolean('look', 'statusbar'):
- # self.statusBar().showMessage(status)
- #self.network.debug_print(0, '', status, forcecolor='#0000AA')
- #self.network_status_set(status)
- print(f"Status is {status}")
+ if status == network.STATUS_DISCONNECTED:
+ self.handle_disconnect()
def _network_weechat_msg(self, source_object, message):
"""Called when a message is received from WeeChat."""
- #print(f"Message {message}")
try:
proto = protocol.Protocol()
message = proto.decode(message.get_data())
@@ -99,6 +111,10 @@ class WeegtkApplication(Adw.Application):
win = self.props.active_window
if not win:
win = WeegtkWindow(application=self)
+ welcome = WeegtkWelcome()
+ welcome.connect("connect-network", self.connect_to_weechat)
+ self.welcome_page = win.stack.add_named(welcome, "welcome")
+ win.set_page(self.welcome_page)
win.present()
def on_about_action(self, *args):
@@ -148,11 +164,8 @@ class WeegtkApplication(Adw.Application):
for obj in message.objects:
if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer':
continue
- #self.list_buffers.clear()
- #while self.stacked_buffers.count() > 0:
- # buf = self.stacked_buffers.widget(0)
- # self.stacked_buffers.removeWidget(buf)
- self.buffers = []
+
+ self.clear_buffers()
for item in obj.value['items']:
buf = self.create_buffer(item)
self.insert_buffer(len(self.buffers), buf)
@@ -323,8 +336,9 @@ class WeegtkApplication(Adw.Application):
# Only make chats visible on main screen
if True or buf.is_chat():
- test_label = Gtk.Label(label="Hello")
- self.props.active_window.stack.add_titled(buf, name=buf_name, title=buf_name)
+ page = self.props.active_window.stack.add_titled(buf, name=buf_name, title=buf_name)
+ if buf.data["full_name"] == "core.weechat":
+ self.props.active_window.set_page(page)
def buffer_input(self, source_object, full_name, text):
if self.network.is_connected():
@@ -335,3 +349,4 @@ def main(version):
"""The application's entry point."""
app = WeegtkApplication()
return app.run(sys.argv)
+
diff --git a/src/meson.build b/src/meson.build
index 649a19e..081477c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -34,6 +34,7 @@ weegtk_sources = [
'chat.py',
'message.py',
'preferences.py',
+ 'welcome.py',
'relay/network.py',
'relay/protocol.py',
'relay/color.py',
diff --git a/src/preferences.py b/src/preferences.py
index 1a87e29..8e6d150 100644
--- a/src/preferences.py
+++ b/src/preferences.py
@@ -28,6 +28,7 @@ import os
class WeegtkPreferences(Adw.PreferencesDialog):
__gtype_name__ = 'WeegtkPreferences'
+ autoconnect = Gtk.Template.Child()
hostname = Gtk.Template.Child()
port = Gtk.Template.Child()
password = Gtk.Template.Child()
@@ -46,6 +47,7 @@ class WeegtkPreferences(Adw.PreferencesDialog):
self.config = config.read()
+ self.autoconnect.set_active(config.str_to_bool(self.config["relay"]["autoconnect"]))
self.hostname.set_text(self.config["relay"]["hostname"])
self.port.set_text(self.config["relay"]["port"])
self.password.set_text(self.config["relay"]["password"])
@@ -60,6 +62,7 @@ class WeegtkPreferences(Adw.PreferencesDialog):
self.install_action("ssh_key.open", None, self.ssh_key_open)
def read_preferences(self):
+ self.config["relay"]["autoconnect"] = str(self.autoconnect.get_active())
self.config["relay"]["hostname"] = self.hostname.get_text()
self.config["relay"]["port"] = self.port.get_text()
self.config["relay"]["password"] = self.password.get_text()
diff --git a/src/relay/network.py b/src/relay/network.py
index 4308ecf..b502ddd 100644
--- a/src/relay/network.py
+++ b/src/relay/network.py
@@ -212,7 +212,7 @@ class Network(GObject.GObject):
"""Slot: data available on socket."""
try:
gbytes = self.input.read_bytes_finish(res)
- except GLib.Error as err:
+ except GLib.GError as err:
self.handle_network_error(err)
return
@@ -281,6 +281,9 @@ class Network(GObject.GObject):
except ValueError:
self._lines = config.CONFIG_DEFAULT_RELAY_LINES
+ if self.cancel_network_reads.is_cancelled():
+ self.cancel_network_reads.reset()
+
# TODO handle SSL
self._socketclient.connect_async(
Gio.NetworkAddress.new(self._hostname, self._port),
@@ -306,15 +309,33 @@ class Network(GObject.GObject):
def disconnect_weechat(self):
"""Disconnect from WeeChat."""
- if self._socket.state() == QtNetwork.QAbstractSocket.UnconnectedState:
- self.set_status(STATUS_DISCONNECTED)
+ if not self._socket.is_connected():
return
- if self._socket.state() == QtNetwork.QAbstractSocket.ConnectedState:
- self.send_to_weechat('quit\n')
- self._socket.waitForBytesWritten(1000)
else:
+ self.send_to_weechat('quit\n')
+ self._socket.set_graceful_disconnect(True)
+ self._socket.close()
+ self._socket = None
+ self.cancel_network_reads.cancel()
+ self.ssh_tunnel.stop()
+ self.ssh_tunnel = None
self.set_status(STATUS_DISCONNECTED)
- self._socket.abort()
+
+ def handle_network_error(self, err):
+ if err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED):
+ print("Connection has been canceled by user.")
+ return
+ elif err.matches(Gio.tls_error_quark(), Gio.TlsError.EOF):
+ print("Server has closed the connection.")
+ return
+ elif err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.BROKEN_PIPE):
+ print("Broken pipe, connection lost.")
+ return
+ elif err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.TIMED_OUT):
+ print("Connection timed out.")
+ return
+ else:
+ raise
def send_to_weechat(self, message):
"""Send a message to WeeChat."""
@@ -402,3 +423,4 @@ class Network(GObject.GObject):
self.debug_dialog.chat.scroll_bottom()
+
diff --git a/src/weegtk.gresource.xml b/src/weegtk.gresource.xml
index c54ffe8..9b7746a 100644
--- a/src/weegtk.gresource.xml
+++ b/src/weegtk.gresource.xml
@@ -6,6 +6,7 @@
<file preprocess="xml-stripblanks">gtk/chat.ui</file>
<file preprocess="xml-stripblanks">gtk/message.ui</file>
<file preprocess="xml-stripblanks">gtk/preferences.ui</file>
+ <file preprocess="xml-stripblanks">gtk/welcome.ui</file>
<file compressed="true">style.css</file>
</gresource>
</gresources>
diff --git a/src/welcome.py b/src/welcome.py
new file mode 100644
index 0000000..96bc0e6
--- /dev/null
+++ b/src/welcome.py
@@ -0,0 +1,38 @@
+# welcome.py
+#
+# Copyright 2024 Lucas Fryzek
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+from gi.repository import Adw, Gtk, GObject
+
+@Gtk.Template(resource_path='/com/fryzekconcepts/weegtk/gtk/welcome.ui')
+class WeegtkWelcome(Adw.Bin):
+ __gtype_name__ = 'WeegtkWelcome'
+
+ __gsignals__ = {
+ "connect-network" : (
+ GObject.SignalFlags.RUN_FIRST,
+ None,
+ ()
+ )
+ }
+
+ def __init__(self, data=None, **kwargs):
+ super().__init__(**kwargs)
+
+ @Gtk.Template.Callback()
+ def connect_network(self, *args):
+ self.emit("connect-network")
diff --git a/src/window.py b/src/window.py
index df63e36..8a4eab7 100644
--- a/src/window.py
+++ b/src/window.py
@@ -28,6 +28,7 @@ class WeegtkWindow(Adw.ApplicationWindow):
content_page = Gtk.Template.Child()
color_scheme_button = Gtk.Template.Child()
split_view = Gtk.Template.Child()
+ primary_menu = Gtk.Template.Child()
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -41,6 +42,9 @@ class WeegtkWindow(Adw.ApplicationWindow):
self.notify_system_supports_color_schemes_cb()
self.notify_visible_child_cb()
+ def set_connect_label(self):
+ pass
+
def notify_system_supports_color_schemes_cb(self):
manager = Adw.StyleManager.get_default()
supports = manager.get_system_supports_color_schemes()
@@ -57,9 +61,14 @@ class WeegtkWindow(Adw.ApplicationWindow):
if child is None:
return
page = self.stack.get_page(child)
- self.content_page.set_title(page.get_title())
+ page_title = "Weegtk" if page.get_title() is None else page.get_title()
+ self.content_page.set_title(page_title)
self.split_view.set_show_content(True)
+ def set_page(self, page):
+ page_name = page.get_name()
+ self.stack.set_visible_child_name(page_name)
+
@Gtk.Template.Callback()
def get_color_scheme_icon_name(self, user_data, dark):
return "light-mode-symbolic" if dark else "dark-mode-symbolic"
@@ -68,3 +77,4 @@ class WeegtkWindow(Adw.ApplicationWindow):
def color_scheme_button_clicked_cb(self, *args):
raise NotImplementedError
+
diff --git a/src/window.ui b/src/window.ui
index efc7d87..54646e9 100644
--- a/src/window.ui
+++ b/src/window.ui
@@ -5,6 +5,12 @@
<menu id="primary_menu">
<section>
<item>
+ <attribute name="label" translatable="yes">_Disconnect</attribute>
+ <attribute name="action">app.disconnect</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
<attribute name="label" translatable="yes">_Preferences</attribute>
<attribute name="action">app.preferences</attribute>
</item>