Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add goroutine6 #70

Merged
merged 8 commits into from
Dec 30, 2024
Merged

Add goroutine6 #70

merged 8 commits into from
Dec 30, 2024

Conversation

rcalixte
Copy link
Contributor

Ported from:
https://github.com/therecipe/examples/blob/master/advanced/widgets/goroutine/main.go

The labels and the goroutines sometimes freeze until the window focus is changed or the window is moved. I tried different time values but wasn't able to have a 100% consistent execution. It works well enough for an example hopefully.

@mappu
Copy link
Owner

mappu commented Nov 11, 2024

This is a really good example, and I think the stuttering shows that goroutines must currently be handled slightly differently in MIQT. It is possible to make this perfectly smooth, but MIQT does not yet have an equivalent to therecipe/qt's label.UpdateTextFromGoroutine method.

I'd like to fix the bug and make it smooth before merging it. This is also related to #72.

Probably the fix is either

  • (Fix Go-side): the goroutine should push to a channel, and the main thread should pull channel events (but this needs a way to integrate with the blocking Exec() call); or else
  • (Fix Qt-side): emit a signal with a callback parameter, which can always be caught and executed on the main event loop

@mappu mappu added the blocked A blocker prevents this from progressing label Nov 17, 2024
@mappu mappu removed the blocked A blocker prevents this from progressing label Dec 29, 2024
@mappu
Copy link
Owner

mappu commented Dec 29, 2024

Fixes: #76

Fixes: #111

Hi @rcalixte - I had some time today to work on this.

The therecipe/qt version of this example used a label.UpdateTextFromGoroutine function so that the update would happen in the correct Qt thread. I've added a new qt6/mainthread package that does the equivalent thing, using QMetaObject::invokeMethod as described in https://stackoverflow.com/a/21653558 .

In my testing:

  • No mainthread, no time.Sleep: Code hangs after some small number of updates
  • With time.Sleep: Works fine but has choppy rendering
  • With mainthread: Works fine with smooth rendering.

Although, the queue seems pretty unfairly distributed on my machine:

goroutine6

I thought Qt::QueuedConnection used a FIFO queue, so i'm surprised the results are this skewed. I'd like to understand that more (and add a Qt5 version) but then I think this MR is good to go,

@rcalixte
Copy link
Contributor Author

I hope

I thought Qt::QueuedConnection used a FIFO queue, so i'm surprised the results are this skewed. I'd like to understand that more (and add a Qt5 version) but then I think this MR is good to go,

We're both learning as we go. I'll give the merged version a run through to see what happens. I'd noticed other artifacts on my end like the window sometimes stalling unless it was focused and other odd behaviors.

Regarding Qt5, with the EOL date set for May 2025 by upstream, are you planning on maintaining the bindings after that point?

@mappu
Copy link
Owner

mappu commented Dec 29, 2024

Regarding Qt5, with the EOL date set for May 2025 by upstream, are you planning on maintaining the bindings after that point?

Qt 5 is still pretty widely used I think. LTS linux distros are still on KDE Plasma 5.15, so Qt 5 is the "native" Qt. And Ubuntu people say it is "pessimistic" ^1 to fully remove Qt 5 by 2026. Personally at $DAYJOB it's a problem because Qt 6 dropped support for old versions of Windows, that customers stubbornly keep using.

So yes, likely Qt 5 support will remain in Miqt for a while longer, as long as it doesn't cause any problems. Everything is well automated so it seems harmless to leave it there. I think the only impending problem could be if qt5 development packages go missing from common distros, that could make it hard to run genbindings, so maybe it could be optional there.

@mappu
Copy link
Owner

mappu commented Dec 29, 2024

Oh, i misread the example, the skew is intentional.

If you do this

-				for range time.NewTicker(time.Duration((index+1)*25) * time.Millisecond).C {
+				for range time.NewTicker(25 * time.Millisecond).C {

then the skew is perfectly distributed:

image

@rcalixte
Copy link
Contributor Author

Qt 5 is still pretty widely used I think. LTS linux distros are still on KDE Plasma 5.15, so Qt 5 is the "native" Qt. And Ubuntu people say it is "pessimistic" ^1 to fully remove Qt 5 by 2026. Personally at $DAYJOB it's a problem because Qt 6 dropped support for old versions of Windows, that customers stubbornly keep using.

GTK 2 was only recently cleaned up so I think the Qt 5 packages may linger longer for sure, especially for smaller projects that don't have the resources to migrate. Debian 13 (currently Testing) has migrated to KDE 6 and Ubuntu has already had a non-LTS release with KDE 6, meaning the next LTS there will be KDE 6 as well. I guess as long as there are packages shipped for dynamic binding, it won't hurt to keep them available, especially since they won't be changing unless there are bugs or other issues discovered.

I think the only impending problem could be if qt5 development packages go missing from common distros, that could make it hard to run genbindings, so maybe it could be optional there.

Agreed. I think that will take a while too.

Oh, i misread the example, the skew is intentional.

That makes both of us. 😅

@rcalixte
Copy link
Contributor Author

That reminds me... Have you given thought to separating out the examples to a dedicated repo to separate the licensing concern? If the explanation that was given to me is correct, LGPL code directly copied or statically linked must be LGPL but code based on LGPL code that does not violate those constraints are free to whatever license they would like.

This is pertinent for two key reasons:

  1. Both languages that I am working on would be novel so if this is correct, there wouldn't be any LGPL concerns (I was previously going to dual license but will likely make everything MIT in that case). While these bindings are novel, other Go bindings and therefore examples exist with similar API conventions, meaning the licensing is a little blurrier there.
  2. The main thing for me is that I would like to keep the examples for all of the projects as synchronized as possible so once I get around to that phase of my progress, I would like to PR everything where needed without licensing concerns.

@mappu
Copy link
Owner

mappu commented Dec 29, 2024

Have you given thought to separating out the examples to a dedicated repo to separate the licensing concern? If the explanation that was given to me is correct, LGPL code directly copied or statically linked must be LGPL but code based on LGPL code that does not violate those constraints are free to whatever license they would like.

By default, code is copyrighted by its author, who reserves all rights. The author then licensed it under the terms of the LGPL; any use outside what is permitted by the LGPL is a violation of the author's copyright.

In particular, the LGPL says that any derived work (Conveying Modified Source Versions) must remain LGPL (You may convey a work based on the Program [...] provided that [...] You must license the entire work, as a whole, under [the GPL/LGPL]. [...] This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.)

It can be a fuzzy line as to what constitutes a "derived work".

I think this goroutine6 example is fine. Looking at them both, miqt's version is really quite different (no signal, no constructor, ...) - the parts that are the same as therecipe's version are really trivial cosmetic things (the layout of two widgets?), and in my opinion, that probably falls below the threshold of originality for copyright enforcement. Miqt is very clearly not a derived work of therecipe/qt.

However, if you were to port the entire set of therecipe's examples, that would definitely be a copyrightable body of work.

There are some options:

  1. Port all the examples, put them in the main repo, with special notice files saying "this file/folder is LGPL licensed".
    • SPDX-License-Identifier: comments are common to use for this.
  2. Port all the examples, put them in a separate repo.
    • I think this is better, it's really simpler if the repo is licensed as a whole. But, it has the downside of being complicated to synchronize, especially when there are breaking changes in the bindings.
  3. Come up with new examples that demonstrate the same concepts.
    • This one's my favorite option. Miqt already has many new unique examples (mdoutliner, libraries/xx, ...) all MIT licensed already. If you understand the concept well enough to create bindings for it, then, making a short example should not be difficult.

@rcalixte
Copy link
Contributor Author

However, if you were to port the entire set of therecipe's examples, that would definitely be a copyrightable body of work.

I was not planning on doing this so we should be okay there.

There are some options:

I was thinking that it would merit having examples that cover implemented functionality, almost as a sort of validation for the bindings and the codegen in one fell swoop. That is, verification of the QList methods with one example should suffice for all of the implementations. (Please correct me if I'm wrong here as it is an assumption I've been leveraging on my end.) That being said, MD Outliner is very much robust enough to cover many use cases, including language semantics for implementing certain functionality. (Go's receiver functions really are a cheat code here. 😅) In a similar vein, this particular example was simple enough to highlight Goroutines (and it served its purpose in identifying a potential issue). So I'm thinking we can have robust examples but also not too numerous, unless the bindings grow that much more in the scope that they cover. I also haven't yet tried to implement this in another language or even adding back the actual Goroutine calls. I haven't gotten around to really digging into the examples yet but I do wonder if language-specific examples might merit a break from my planned synchronization.

Lots of words, but the main thing is that this is still a little bit away from being top of mind or somewhere I'm investing too much time at the moment. It is important but I am treating it as validation of the bindings and eventually a test suite when the time comes. Ultimately, I hope to have the examples serve as the canaries should some issue arise. Top of mind, I see the open issue for Events so I definitely want to make sure that works. I tested subclasses on my own but I really want to have a thorough example here at some point.

@mappu mappu merged commit 12618a3 into mappu:master Dec 30, 2024
5 checks passed
@rcalixte rcalixte deleted the goroutine6 branch December 30, 2024 04:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants