From 0bfb140dc73116ecdbee216a443503680ef9fb0f Mon Sep 17 00:00:00 2001 From: sunglocto Date: Thu, 30 Apr 2026 14:55:17 +0100 Subject: [PATCH] Fix lag issues --- assets.go | 4 ++ gtk-helpers.go | 75 +++++++++++++++++++++++++- gtk-message.go | 31 ++++++----- main.go | 136 +++++++++++++++++++++++++++++------------------- xmpp-helpers.go | 47 ++++++++++++++++- 5 files changed, 223 insertions(+), 70 deletions(-) diff --git a/assets.go b/assets.go index e20202a..0a52522 100644 --- a/assets.go +++ b/assets.go @@ -137,6 +137,9 @@ var mucTemporaryBytes []byte //go:embed assets/moderate.png var moderateBytes []byte +//go:embed assets/jabber.png +var jabberBytes []byte + func loadAsset(key string, data []byte) { loader := gdkpixbuf.NewPixbufLoader() loader.Write(data) @@ -189,6 +192,7 @@ func init() { "muc_persistent": mucPersistentBytes, "muc_temporary": mucTemporaryBytes, "moderate": moderateBytes, + "jabber": jabberBytes, } { loadAsset(key, data) } diff --git a/gtk-helpers.go b/gtk-helpers.go index e0db50a..952bde6 100644 --- a/gtk-helpers.go +++ b/gtk-helpers.go @@ -73,9 +73,13 @@ func switchToTab(jid string, w *gtk.Window) { i := 0 rangeOrdered(&mm, (func(k, v any) bool { i++ + u, ok := v.(stanza.Presence) + if !ok { + return true + } + userbox := gtk.NewBox(gtk.OrientationHorizontal, 2) - u := v.(stanza.Presence) var mu MucUser var ocu OccupantID u.Get(&mu) @@ -103,7 +107,7 @@ func switchToTab(jid string, w *gtk.Window) { userbox.Append(nick_label) var hats Hats - ok := u.Get(&hats) + ok = u.Get(&hats) if ok { for _, hat := range hats.Hats { var val float64 @@ -531,3 +535,70 @@ func createIdenticon(word string) *gtk.Image { // This function generates an ide return i } + +func jidBuilder(en *gtk.Entry) { // This function spawns a window that allows the user to interactively build a JID + // TODO: Localise this + + win := gtk.NewWindow() + win.SetTitle("Build-A-JID") + win.SetDefaultSize(400, 1) + win.SetResizable(false) + + box := gtk.NewBox(gtk.OrientationVertical, 2) + header := gtk.NewLabel("Build-A-JID") + header.AddCSSClass("author") + box.Append(header) + + box.Append(gtk.NewLabel("All fields except for domain are optional")) + + jid_builder := gtk.NewBox(gtk.OrientationHorizontal, 2) + + localPartEntry := gtk.NewEntry() + localPartEntry.SetPlaceholderText("localpart") + jid_builder.Append(localPartEntry) + + at_sign := gtk.NewLabel("@") + at_sign.AddCSSClass("author") + jid_builder.Append(at_sign) + + domainEntry := gtk.NewEntry() + domainEntry.SetPlaceholderText("domain") + jid_builder.Append(domainEntry) + + resource_sign := gtk.NewLabel("/") + resource_sign.AddCSSClass("author") + jid_builder.Append(resource_sign) + + resourceEntry := gtk.NewEntry() + resourceEntry.SetPlaceholderText("resource") + jid_builder.Append(resourceEntry) + + box.Append(jid_builder) + + submit := gtk.NewButtonWithLabel(loadedLocale["submit"]) + submit.ConnectClicked(func() { + localPart := localPartEntry.Text() + domain := domainEntry.Text() + resource := resourceEntry.Text() + at := "@" + slash := "/" + + if localPart == "" { + at = "" + } + + if resource == "" { + slash = "" + } + + jid := localPart + at + domain + slash + resource + + en.SetText(jid) + win.SetVisible(false) + }) + + box.Append(submit) + + win.SetChild(box) + win.SetVisible(true) +} diff --git a/gtk-message.go b/gtk-message.go index aa87c52..96130fc 100644 --- a/gtk-message.go +++ b/gtk-message.go @@ -7,6 +7,7 @@ import ( "encoding/base64" "fmt" "github.com/diamondburned/gotk4/pkg/gdk/v4" + "github.com/diamondburned/gotk4/pkg/glib/v2" "github.com/diamondburned/gotk4/pkg/gtk/v4" "github.com/google/uuid" "github.com/jacoblockett/sanitizefilename" @@ -155,35 +156,39 @@ func generateMessageWidget(p stanza.Packet) gtk.Widgetter { // authorBox.Append(im) - n := jid.MustParse(m.From).Resourcepart() + n := JidMustParse(m.From).Resource if n == "" { - n = jid.MustParse(m.From).String() + n = JidMustParse(m.From).Resource } al := gtk.NewLabel(n) al.AddCSSClass("author") al.SetSelectable(true) if m.Type == stanza.MessageTypeGroupchat { - mo, _ := mucmembers.Load(jid.MustParse(m.From).Bare().String()) + mo, _ := mucmembers.Load(JidMustParse(m.From).Bare()) mm := mo.(mucUnit) mmm := mm.Members mmmm, ok := mmm.Load(id) if ok { pres := mmmm.(stanza.Presence) - var vu VCardUpdate pres.Get(&vu) + im := createIdenticon(m.From) + im.SetPixelSize(40) + im.AddCSSClass("author_img") + authorBox.Append(im) if vu.Photo != "" { - im := getAvatar(m.From, vu.Photo) - im.SetPixelSize(40) - im.AddCSSClass("author_img") - authorBox.Append(im) - } else { - im := createIdenticon(m.From) - im.SetPixelSize(40) - im.AddCSSClass("author_img") - authorBox.Append(im) + go func() { + new_im := getAvatar(m.From, vu.Photo) + glib.IdleAdd(func() { + new_im.SetPixelSize(40) + new_im.AddCSSClass("author_img") + authorBox.Remove(im) + authorBox.Prepend(new_im) + }) + }() } + } else { im := createIdenticon(m.From) im.SetPixelSize(40) diff --git a/main.go b/main.go index 7405ab5..bc66d07 100644 --- a/main.go +++ b/main.go @@ -219,7 +219,9 @@ func main() { */ originator := JidMustParse(m.From).Bare() - mStatus.SetText(originator) + glib.IdleAdd(func() { + mStatus.SetText(originator) + }) at := new(Attention) ok = m.Get(at) @@ -280,7 +282,6 @@ func main() { } glib.IdleAdd(func() { - //uiQueue <- func() { b := gtk.NewBox(gtk.OrientationVertical, 0) tab, ok := tabs.Load(originator) @@ -303,7 +304,6 @@ func main() { if ok { b.Append(ba) } - //} }) }) @@ -464,11 +464,13 @@ func main() { return } _ = <-mychan - - pingStatus.RemoveCSSClass("pending") delay := time.Since(before) / time.Millisecond - pingStatus.SetText(fmt.Sprintf("%d %s", delay, loadedLocale["milliseconds"])) pingTimes[0] = append(pingTimes[0], float64(delay)) + + glib.IdleAdd(func() { + pingStatus.RemoveCSSClass("pending") + pingStatus.SetText(fmt.Sprintf("%d %s", delay, loadedLocale["milliseconds"])) + }) }() } @@ -480,28 +482,30 @@ func main() { go func() { for { time.Sleep(1 * time.Second) - stat, err := xmlLog.Stat() - if err != nil { - panic(err) - } + glib.IdleAdd(func() { + stat, err := xmlLog.Stat() + if err != nil { + panic(err) + } - newsize = stat.Size() - diff := float64(newsize-oldsize) / 1000 + newsize = stat.Size() + diff := float64(newsize-oldsize) / 1000 - if diff > 100 { - sIcon.SetFromPaintable(clientAssets["car_high"]) - } else { - sIcon.SetFromPaintable(clientAssets["car"]) - } - - sStatus.SetText(fmt.Sprintf("%.2f%s", diff, loadedLocale["KBPerSecond"])) - oldsize = stat.Size() + ic := clientAssets["car"] + if diff >= 25 { + ic = clientAssets["car_high"] + } + sStatus.SetText(fmt.Sprintf("%.2f%s", diff, loadedLocale["KBPerSecond"])) + sIcon.SetFromPaintable(ic) + }) } }() - connectionStatus.SetText(fmt.Sprintf("%s%s", loadedLocale["connectedAs"], JidMustParse(clientroot.Session.BindJid).Bare())) - connectionStatus.SetTooltipText(fmt.Sprintf("%s%s\n%s%t", loadedLocale["bindedJid"], clientroot.Session.BindJid, loadedLocale["usingTLS"], clientroot.Session.TlsEnabled)) - connectionIcon.SetFromPaintable(clientAssets["connect"]) + glib.IdleAdd(func() { + connectionStatus.SetText(fmt.Sprintf("%s%s", loadedLocale["connectedAs"], JidMustParse(clientroot.Session.BindJid).Bare())) + connectionStatus.SetTooltipText(fmt.Sprintf("%s%s\n%s%t", loadedLocale["bindedJid"], clientroot.Session.BindJid, loadedLocale["usingTLS"], clientroot.Session.TlsEnabled)) + connectionIcon.SetFromPaintable(clientAssets["connect"]) + }) // Enable carbons client.SendRaw(fmt.Sprintf( ` 0 { @@ -633,8 +636,26 @@ func activate(app *gtk.Application) { aboutAction := gio.NewSimpleAction("about", nil) aboutAction.ConnectActivate(func(p *glib.Variant) { - a := gtk.AboutDialog{} - a.SetVisible(true) + a := gtk.NewAboutDialog() + about_window := gtk.NewWindow() + about_window.SetTransientFor(&window.Window) + about_window.SetTitle(fmt.Sprintf("%s %s", "About", loadedLocale["appName"])) + a.SetProgramName("Lambda") + a.SetVersion(lambda_version) + a.SetComments("yet another XMPP client") + a.SetAuthors([]string{"Sunglocto"}) + a.SetLicense("GPL3") + a.SetWebsite("https://forge.sunglocto.net/sunglocto/lambda") + a.SetWebsiteLabel("Website") + + /* + a.ConnectResponse(func() { + about_window.SetVisible(false) + }) + */ + about_window.SetChild(a) + about_window.SetDefaultSize(400, 300) + about_window.SetVisible(true) }) destroymucAction := gio.NewSimpleAction("destroymuc", nil) @@ -743,7 +764,16 @@ func activate(app *gtk.Application) { nick_entry.SetText(loadedConfig.Nick) + create_jid := gtk.NewImageFromPaintable(clientAssets["jabber"]) + gesture := gtk.NewGestureClick() + gesture.SetButton(1) + gesture.Connect("pressed", func() { + jidBuilder(jid_entry) + }) + create_jid.AddController(gesture) + jid_box.Append(gtk.NewLabel(loadedLocale["joinMUCJIDEntry"])) + jid_box.Append(create_jid) jid_box.Append(jid_entry) nick_box.Append(gtk.NewLabel(loadedLocale["joinMUCNickEntry"])) @@ -946,7 +976,7 @@ func activate(app *gtk.Application) { app.AddAction(aboutAction) app.AddAction(destroymucAction) - the_menu.AppendSubmenu("File", fileMenu) + the_menu.AppendSubmenu("MUC", fileMenu) the_menu.AppendSubmenu("Help", helpMenu) the_menuBar := gtk.NewPopoverMenuBarFromModel(the_menu) diff --git a/xmpp-helpers.go b/xmpp-helpers.go index 211f58c..0f4fd6e 100644 --- a/xmpp-helpers.go +++ b/xmpp-helpers.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "gosrc.io/xmpp" "gosrc.io/xmpp/stanza" ) @@ -31,7 +30,6 @@ func sendMessage(c xmpp.Sender, sendTo string, msgType stanza.StanzaType, body s func joinMuc(c xmpp.Sender, jid string, muc string, nick string, password string) error { var joinPresence stanza.Presence addr := muc + "/" + nick - fmt.Println(addr) if password == "" { joinPresence = stanza.Presence{ Attrs: stanza.Attrs{ @@ -63,6 +61,51 @@ func joinMuc(c xmpp.Sender, jid string, muc string, nick string, password string return nil } +func joinMucWithoutHistory(c xmpp.Sender, jid string, muc string, nick string, password string) error { + var joinPresence stanza.Presence + addr := muc + "/" + nick + if password == "" { + joinPresence = stanza.Presence{ + Attrs: stanza.Attrs{ + From: jid, + To: addr, + }, + Extensions: []stanza.PresExtension{ + &stanza.MucPresence{ + History: stanza.History{ + MaxChars: stanza.NewNullableInt(0), + MaxStanzas: stanza.NewNullableInt(0), + Seconds: stanza.NewNullableInt(0), + }, + }, + }, + } + } else { + joinPresence = stanza.Presence{ + Attrs: stanza.Attrs{ + From: jid, + To: addr, + }, + Extensions: []stanza.PresExtension{ + &stanza.MucPresence{ + Password: password, + History: stanza.History{ + MaxChars: stanza.NewNullableInt(0), + MaxStanzas: stanza.NewNullableInt(0), + Seconds: stanza.NewNullableInt(0), + }, + }, + }, + } + } + + err := client.Send(joinPresence) + if err != nil { + return err + } + return nil +} + // jid MustParse but using gosrc's instead of mellium // This function will panic if its an invalid JID