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

Re-consider Qt #327

Closed
emoon opened this Issue Sep 7, 2016 · 26 comments

Comments

Projects
None yet
10 participants
@emoon
Owner

emoon commented Sep 7, 2016

After doing some UI work and looking over the existing work that is left considering Qt again might actually be the correct way forward.

One of the reasons of switch from Qt was slow compile times and large library. Those things won't go away but as the project is growing it may become less of an issue.

The other reason for switching was poor performance. I have been pointed out that the current implementation we had of the HexView could have been done much faster.

So, while annoying (and spending quite a bit of the on the imgui UI) perhaps doing some prototyping and investigating, looking into Rust bindings for Q.

@SlNPacifist

This comment has been minimized.

Show comment
Hide comment
@SlNPacifist

SlNPacifist Sep 9, 2016

Collaborator

I have been pointed out that the current implementation we had of the HexView could have been done much faster.

By "faster" you mean that it could be implemented faster or it could work faster (consuming less CPU)?

Collaborator

SlNPacifist commented Sep 9, 2016

I have been pointed out that the current implementation we had of the HexView could have been done much faster.

By "faster" you mean that it could be implemented faster or it could work faster (consuming less CPU)?

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 9, 2016

Owner

Yes. The problem was that it was quite slow (CPU wise in Qt) I'm very convinced it can be implemented with less code in Qt.

Owner

emoon commented Sep 9, 2016

Yes. The problem was that it was quite slow (CPU wise in Qt) I'm very convinced it can be implemented with less code in Qt.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 18, 2016

Owner

Wrote a long post about this and UI's in general over here http://prodbg.com/rethinking-ui

Owner

emoon commented Sep 18, 2016

Wrote a long post about this and UI's in general over here http://prodbg.com/rethinking-ui

@meeloo

This comment has been minimized.

Show comment
Hide comment
@meeloo

meeloo Sep 19, 2016

You could also have a look at https://github.com/libnui/nui3/ . I used it to write a GUI for LLDB as well (more a proof of concept than anything useful): https://github.com/meeloo/xspray
NUI works fine on macOS/iOS and used to work on linux and windows (I haven't had the time to support those ports for some years unfortunately, but reviving is doable).

meeloo commented Sep 19, 2016

You could also have a look at https://github.com/libnui/nui3/ . I used it to write a GUI for LLDB as well (more a proof of concept than anything useful): https://github.com/meeloo/xspray
NUI works fine on macOS/iOS and used to work on linux and windows (I haven't had the time to support those ports for some years unfortunately, but reviving is doable).

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 19, 2016

Owner

@meeloo Thanks I will take a look. I have to make sure to pick something that is support on Mac/Linux and Windows though. Even if Qt is very big it's also widely supported and has a team working on it.

Owner

emoon commented Sep 19, 2016

@meeloo Thanks I will take a look. I have to make sure to pick something that is support on Mac/Linux and Windows though. Even if Qt is very big it's also widely supported and has a team working on it.

@olafurw

This comment has been minimized.

Show comment
Hide comment
@olafurw

olafurw Sep 19, 2016

Have you looked at CEF? We use it and it's wonderful, you control the chrome version so no HTML/JS cross compatibility to worry about, it's super flexible, you benefit from all the millions of JS frameworks and it's easy for anyone to jump into and work with the UI and sending messages back and forth is just a matter of JSON between the layers.

olafurw commented Sep 19, 2016

Have you looked at CEF? We use it and it's wonderful, you control the chrome version so no HTML/JS cross compatibility to worry about, it's super flexible, you benefit from all the millions of JS frameworks and it's easy for anyone to jump into and work with the UI and sending messages back and forth is just a matter of JSON between the layers.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 19, 2016

Owner

@olafurw I haven't but I heard horror stories about building large applications in JS. I will investigate non the less, thanks!

Owner

emoon commented Sep 19, 2016

@olafurw I haven't but I heard horror stories about building large applications in JS. I will investigate non the less, thanks!

@olafurw

This comment has been minimized.

Show comment
Hide comment
@olafurw

olafurw Sep 19, 2016

We have a pretty big application where the frontend is all in JS, I would recommend decoupling data and views and setup some sort of data bus where all data is requested through so views never have to worry, the UI should be stupid and fed data from the application end. Works pretty well.

olafurw commented Sep 19, 2016

We have a pretty big application where the frontend is all in JS, I would recommend decoupling data and views and setup some sort of data bus where all data is requested through so views never have to worry, the UI should be stupid and fed data from the application end. Works pretty well.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 19, 2016

Owner

@olafurw alright. Thanks for the info!

Owner

emoon commented Sep 19, 2016

@olafurw alright. Thanks for the info!

@bmharper

This comment has been minimized.

Show comment
Hide comment
@bmharper

bmharper Sep 19, 2016

Where do you perceive the pain related to plugins including and linking to QT? If Windows compilation - Microsoft is going to release a C/C++ package manager very soon (vcpkg last time I saw it's name), which might remove the last big platform that doesn't have a painless "-dev" package installation system. If a plugin author simply needs to go "apt-get install qt-dev", or "vcpkg install qt", etc, then maybe it's really not so bad.

bmharper commented Sep 19, 2016

Where do you perceive the pain related to plugins including and linking to QT? If Windows compilation - Microsoft is going to release a C/C++ package manager very soon (vcpkg last time I saw it's name), which might remove the last big platform that doesn't have a painless "-dev" package installation system. If a plugin author simply needs to go "apt-get install qt-dev", or "vcpkg install qt", etc, then maybe it's really not so bad.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 19, 2016

Owner
  1. Slower link times (main app already links with Qt)
  2. Main app and plugins must have matching Qt version.
  3. As related to 2. if I upgrade main app to Qt 6.0 (or something) all plugins needs to be re-compiled to match. This is quite common on some 3D apps that with a new version all plugins needs to be re-compiled and that sucks.

With my current approach C plugins doesn't need to link with a single library which is very nice.

Owner

emoon commented Sep 19, 2016

  1. Slower link times (main app already links with Qt)
  2. Main app and plugins must have matching Qt version.
  3. As related to 2. if I upgrade main app to Qt 6.0 (or something) all plugins needs to be re-compiled to match. This is quite common on some 3D apps that with a new version all plugins needs to be re-compiled and that sucks.

With my current approach C plugins doesn't need to link with a single library which is very nice.

@Kuranes

This comment has been minimized.

Show comment
Hide comment
@Kuranes

Kuranes Sep 19, 2016

3 Have plugins being totally separate executables and have them communicate with the host app.

3bis: have plugins being coded in 2 parts:

  • a "core side" plugin code
  • separated gui code.

Solve speed/fast problematic, allow clean gui separated code and prevent core side being "slowed down" by gui code (events/etc.).
Just to be sure to include: record/replay RPC communication between gui/core so that unit-testing core side of plugins are robust. (much easier to debug)
May seems complicated, but a big win in the end imho, as gui code tends to pollute codebase very very easily.

Kuranes commented Sep 19, 2016

3 Have plugins being totally separate executables and have them communicate with the host app.

3bis: have plugins being coded in 2 parts:

  • a "core side" plugin code
  • separated gui code.

Solve speed/fast problematic, allow clean gui separated code and prevent core side being "slowed down" by gui code (events/etc.).
Just to be sure to include: record/replay RPC communication between gui/core so that unit-testing core side of plugins are robust. (much easier to debug)
May seems complicated, but a big win in the end imho, as gui code tends to pollute codebase very very easily.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 19, 2016

Owner

@Kuranes That sounds interesting. Care to elaborate more in detail on that?

Owner

emoon commented Sep 19, 2016

@Kuranes That sounds interesting. Care to elaborate more in detail on that?

@Kuranes

This comment has been minimized.

Show comment
Hide comment
@Kuranes

Kuranes Sep 19, 2016

Did that once for a tool with plugins, that had to be run in cli and gui, but in the end the core/gui plugin separated felt very much like a win.

  • plugins added dll (C++ based code) to the core, code that did the real work, each "work" unit of the plugin cleanly organised in "commands" that were registered with name, etc to the main core. (using c++ delegates)
  • plugins gui was optional (plugins could be activated with just cli args ). Plugins gui registered observers on "events" from the core to get updates/visu, and sent RPC "commands" to the core (pluginname/id/parameters)

Unfortunately I cannot seem to find opensource example of that.
( only I can is http://vorlonjs.com/ which does that in js with code in "core" is in the debugged page, and code "gui" is in the dashboard thing)

Kuranes commented Sep 19, 2016

Did that once for a tool with plugins, that had to be run in cli and gui, but in the end the core/gui plugin separated felt very much like a win.

  • plugins added dll (C++ based code) to the core, code that did the real work, each "work" unit of the plugin cleanly organised in "commands" that were registered with name, etc to the main core. (using c++ delegates)
  • plugins gui was optional (plugins could be activated with just cli args ). Plugins gui registered observers on "events" from the core to get updates/visu, and sent RPC "commands" to the core (pluginname/id/parameters)

Unfortunately I cannot seem to find opensource example of that.
( only I can is http://vorlonjs.com/ which does that in js with code in "core" is in the debugged page, and code "gui" is in the dashboard thing)

@Anteru

This comment has been minimized.

Show comment
Hide comment
@Anteru

Anteru Sep 19, 2016

I'd mostly make sure that you can have non-UI plugins and UI plugins. Might turn out that the number of UI plugins in the end is rather small as you can provide some hooks for the plugins to get some UI done (message box, ask for user input, that kind of thing -- similar to what Powershell for example provides.)

On the Qt decision - 👍 for that, I think this is the right way forward.

Anteru commented Sep 19, 2016

I'd mostly make sure that you can have non-UI plugins and UI plugins. Might turn out that the number of UI plugins in the end is rather small as you can provide some hooks for the plugins to get some UI done (message box, ask for user input, that kind of thing -- similar to what Powershell for example provides.)

On the Qt decision - 👍 for that, I think this is the right way forward.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 19, 2016

Owner

Yeah so the way I do it now is that I have backend and view plugins. Backends is for implementing a new debugger backend while views are for displaying some data from a backend.

Right now there is fewer backend than views. Example of backends:

  • LLDB
  • Amiga UAE
  • WinDBG Engine

Views:

  • Disassembly
  • Registers
  • SourceCode
  • Callstack
  • Threads
  • Memory
  • ...

So in my case there will be more view plugins than backends (I would guess at least)

The idea is that each view can do fairly complicated UI stuff so I need to expose a fair amount of the UI API to them in one way in another.

Owner

emoon commented Sep 19, 2016

Yeah so the way I do it now is that I have backend and view plugins. Backends is for implementing a new debugger backend while views are for displaying some data from a backend.

Right now there is fewer backend than views. Example of backends:

  • LLDB
  • Amiga UAE
  • WinDBG Engine

Views:

  • Disassembly
  • Registers
  • SourceCode
  • Callstack
  • Threads
  • Memory
  • ...

So in my case there will be more view plugins than backends (I would guess at least)

The idea is that each view can do fairly complicated UI stuff so I need to expose a fair amount of the UI API to them in one way in another.

@niklasfrykholm

This comment has been minimized.

Show comment
Hide comment
@niklasfrykholm

niklasfrykholm Sep 20, 2016

Performance could probably be solved by only updating the UI when there is a state change (though things like mouseover, etc might be tricky and require special code paths).

I think a functional view on UI (data → view) is most useful. Even in frameworks that are state based (DOM) there is a tendency to move towards functional APIs and then do a "DOM diff" to figure out what state changes to apply.

Getting good performance with CEF/HTML is certainly possible, but as with any top-down solution it can be tricky, because there are a lot of layers. I find it easier to control performance in a bottom-up scenario (i.e. IMGUI or similar).

For plugins, I would try to define an independent API interface so that they don't have to link against and become dependent on Qt (or another UI library). But it is tricky to find a balance between limiting the plugins (by not exposing enough) and exposing so much that the API becomes tightly bound to the backend (whether that is IMGUI /Qt/HTML). Maybe best to provide two levels of API. A high level that just talks about predefined controls (buttons, treeviews, etc) -- and a low level that allows custom drawing and control implementation. That way, "most" plugins can just use the high-level API and only those that need special capabilities need to deal with the low-level API.

What issues with text rendering did you run into? Is this something that just appears when rendering large amounts of text (i.e. documents), or even for small interface strings?

My current take on this is:

  • HTML/Cef is doable, but requires lots of effort that you don't accidentally create performance issues. Nice things are that it can be scripted, tested in browser, reloaded, and you know it will be around and worked on. (Because the web will be around.)
  • Imgui looks attractive, especially for performance/simplicity, but I haven't tried building anything big in it, so I'm not sure what issues you might run into.
  • Qt looks scary to me -- it is a huge DLL, I don't like moc, I don't like class-based designs. But I haven't made anything big with it, so I don't know. Lots of successful applications use it.
  • I wouldn't use anything other than one of these three (wxWidgets, GTK, Fox, etc).
  • How to build UIs in a good way is a hard and still "unsolved" problems. Just look at how many different JavaScript frameworks that keep appearing all the time. Once you've picked a path it is really hard to change, because you will have a lot of UI code.

niklasfrykholm commented Sep 20, 2016

Performance could probably be solved by only updating the UI when there is a state change (though things like mouseover, etc might be tricky and require special code paths).

I think a functional view on UI (data → view) is most useful. Even in frameworks that are state based (DOM) there is a tendency to move towards functional APIs and then do a "DOM diff" to figure out what state changes to apply.

Getting good performance with CEF/HTML is certainly possible, but as with any top-down solution it can be tricky, because there are a lot of layers. I find it easier to control performance in a bottom-up scenario (i.e. IMGUI or similar).

For plugins, I would try to define an independent API interface so that they don't have to link against and become dependent on Qt (or another UI library). But it is tricky to find a balance between limiting the plugins (by not exposing enough) and exposing so much that the API becomes tightly bound to the backend (whether that is IMGUI /Qt/HTML). Maybe best to provide two levels of API. A high level that just talks about predefined controls (buttons, treeviews, etc) -- and a low level that allows custom drawing and control implementation. That way, "most" plugins can just use the high-level API and only those that need special capabilities need to deal with the low-level API.

What issues with text rendering did you run into? Is this something that just appears when rendering large amounts of text (i.e. documents), or even for small interface strings?

My current take on this is:

  • HTML/Cef is doable, but requires lots of effort that you don't accidentally create performance issues. Nice things are that it can be scripted, tested in browser, reloaded, and you know it will be around and worked on. (Because the web will be around.)
  • Imgui looks attractive, especially for performance/simplicity, but I haven't tried building anything big in it, so I'm not sure what issues you might run into.
  • Qt looks scary to me -- it is a huge DLL, I don't like moc, I don't like class-based designs. But I haven't made anything big with it, so I don't know. Lots of successful applications use it.
  • I wouldn't use anything other than one of these three (wxWidgets, GTK, Fox, etc).
  • How to build UIs in a good way is a hard and still "unsolved" problems. Just look at how many different JavaScript frameworks that keep appearing all the time. Once you've picked a path it is really hard to change, because you will have a lot of UI code.
@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 20, 2016

Owner

Thanks for a detailed reply!

What issues with text rendering did you run into? Is this something that just appears when rendering large amounts of text (i.e. documents), or even for small interface strings?

Two things:

  • Supporting various languages (Arabic, Chinese, Thai, etc)
  • Quality of text rendering

Both solvable but time consuming.

I think you are totally right about making an Independent API around the UI and I like the idea about two levels of the API so I will likely try to head in that direction.

I think I will try Qt first. I agree that it's huge and I'm no fan of class-based and the moc stuff either but perhaps all of that can be wrapped away with the Independent API. I wouldn't want to expose that directly because it gets very tied to Qt then. I also ran into this thing https://blog.qt.io/blog/2016/08/18/introducing-the-qt-lite-project-qt-for-any-platform-any-thing-any-size/ So maybe there is something that can be used later on.

wxWidgets is a good candidate also but I would like to look to be same across platforms if possible (which Qt does) but if there is a good abstraction around maybe it would be possible do do anyway.

And yes, UIs are really hard and for sure still "unsolved"

Owner

emoon commented Sep 20, 2016

Thanks for a detailed reply!

What issues with text rendering did you run into? Is this something that just appears when rendering large amounts of text (i.e. documents), or even for small interface strings?

Two things:

  • Supporting various languages (Arabic, Chinese, Thai, etc)
  • Quality of text rendering

Both solvable but time consuming.

I think you are totally right about making an Independent API around the UI and I like the idea about two levels of the API so I will likely try to head in that direction.

I think I will try Qt first. I agree that it's huge and I'm no fan of class-based and the moc stuff either but perhaps all of that can be wrapped away with the Independent API. I wouldn't want to expose that directly because it gets very tied to Qt then. I also ran into this thing https://blog.qt.io/blog/2016/08/18/introducing-the-qt-lite-project-qt-for-any-platform-any-thing-any-size/ So maybe there is something that can be used later on.

wxWidgets is a good candidate also but I would like to look to be same across platforms if possible (which Qt does) but if there is a good abstraction around maybe it would be possible do do anyway.

And yes, UIs are really hard and for sure still "unsolved"

@mrexodia

This comment has been minimized.

Show comment
Hide comment
@mrexodia

mrexodia Sep 29, 2016

I'm the main developer of x64dbg that makes heavy use of Qt. While there are drawbacks (complex threading model and complex parent/child model/hard to profile performance issues) the biggest upside is speedy development, even with custom-drawn widgets. Signals and slots are a great way of working.

I don't quite understand the 'plugin' model of ProDBG but if you are going to make everything a plugin you will be stuck in development hell forever (also if you try to 'wrap' Qt in a C interface). All I provide to plugins is AddQWidgetTab that adds a QWidget* to the main interface and lots of custom APIs that are also used to communicate between the GUI and the backend. My suggestion would be to write various components that each expose a custom interface for plugins and not let plugins manipulate the GUI unless they fully provide it by themselves.

In x64dbg the main challenge has been to optimize custom text drawing (syntax highlighting for disassembly). Qt and fonts are very complex and I would suggest basing your views on QTextEdit and not make them fully custom-drawn.

Oh and yes build time of x64dbg is 15 minutes per architecture and the output is ~60 mb uncompressed but nobody cares because that's what build servers and incremental building are for.

mrexodia commented Sep 29, 2016

I'm the main developer of x64dbg that makes heavy use of Qt. While there are drawbacks (complex threading model and complex parent/child model/hard to profile performance issues) the biggest upside is speedy development, even with custom-drawn widgets. Signals and slots are a great way of working.

I don't quite understand the 'plugin' model of ProDBG but if you are going to make everything a plugin you will be stuck in development hell forever (also if you try to 'wrap' Qt in a C interface). All I provide to plugins is AddQWidgetTab that adds a QWidget* to the main interface and lots of custom APIs that are also used to communicate between the GUI and the backend. My suggestion would be to write various components that each expose a custom interface for plugins and not let plugins manipulate the GUI unless they fully provide it by themselves.

In x64dbg the main challenge has been to optimize custom text drawing (syntax highlighting for disassembly). Qt and fonts are very complex and I would suggest basing your views on QTextEdit and not make them fully custom-drawn.

Oh and yes build time of x64dbg is 15 minutes per architecture and the output is ~60 mb uncompressed but nobody cares because that's what build servers and incremental building are for.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Sep 30, 2016

Owner

Thanks for these insights with some good info to consider. I'm a bit torn on the way forward for sure. My approach will likely be that I experiment a bit and see what level I should put the UI API on or if I should expose Qt directly.

Owner

emoon commented Sep 30, 2016

Thanks for these insights with some good info to consider. I'm a bit torn on the way forward for sure. My approach will likely be that I experiment a bit and see what level I should put the UI API on or if I should expose Qt directly.

@deplinenoise

This comment has been minimized.

Show comment
Hide comment
@deplinenoise

deplinenoise Nov 30, 2016

Collaborator

I bet plenty of stuff doesn't need a real UI beyond a few buttons and checkboxes. These type of things you can support abstractly with an API that allows the plugin to say: "Here's my (typed) set of things and their current values. Let me know if they are changed" - you can map that to Qt or any other widget set on the app side and the plugin ignores the rest. You can get as fancy as you want here, as long as all you need is settings, trees of things, sliders, arrays etc.

But if you want plugins to actually take part in the screen redraw and be first class citizens in the app, then I don't see how you can avoid linking them to the same UI technology the app is using. Whatever level of abstraction you would add in between is probably just going to slow you down.

Recompiling plugins when there's an new Qt version doesn't seem particularly hard to do or even much of a pain. It sucks for commercial software because you typically don't have source, but it's not a big deal for open source stuff. And if someone has a hypothetical plugin that needs Qt 5.7 and you upgrade to 5.8 they can always chose not to get the latest version of ProDBG while they wait for an upgrade of this mystical plugin. This seems like a lot of work to solve a non-problem.

Collaborator

deplinenoise commented Nov 30, 2016

I bet plenty of stuff doesn't need a real UI beyond a few buttons and checkboxes. These type of things you can support abstractly with an API that allows the plugin to say: "Here's my (typed) set of things and their current values. Let me know if they are changed" - you can map that to Qt or any other widget set on the app side and the plugin ignores the rest. You can get as fancy as you want here, as long as all you need is settings, trees of things, sliders, arrays etc.

But if you want plugins to actually take part in the screen redraw and be first class citizens in the app, then I don't see how you can avoid linking them to the same UI technology the app is using. Whatever level of abstraction you would add in between is probably just going to slow you down.

Recompiling plugins when there's an new Qt version doesn't seem particularly hard to do or even much of a pain. It sucks for commercial software because you typically don't have source, but it's not a big deal for open source stuff. And if someone has a hypothetical plugin that needs Qt 5.7 and you upgrade to 5.8 they can always chose not to get the latest version of ProDBG while they wait for an upgrade of this mystical plugin. This seems like a lot of work to solve a non-problem.

@deplinenoise

This comment has been minimized.

Show comment
Hide comment
@deplinenoise

deplinenoise Nov 30, 2016

Collaborator

Having used Qt professionally for a while I can definitely recommend it. In my opinion it's the only cross platform toolkit out there that isn't full-on amateur hour. Stuff actually works across different platforms, and it fits in pretty well with other native apps.

Pros

  • Extremely comprehensive. Basically all the things included.
  • Model/view separation is reasonably well done and enables you to focus on (and unit test) data sources - then hook them up to stock views that are pretty solid in terms of features and performance.
  • Documentation (docs, tutorials, examples) are best in class, especially if you consider other open source projects
  • It's reasonably performant if you follow best practices. It certainly smokes anything we ever had running in a browser by a huge margin.
  • Implicit sharing and read only data structures make concurrency an attractive and easy-to-use option for many tasks. We leverage this heavily to kick off tasks to the thread pool and block the UI thread as rarely as possible.
  • Signals and slots are a clean way to connect random stuff together without crazy coupling.
  • Layouts basically solve the "scalable UI" problem
  • Hi-DPI support is basic but workable in Qt 5. Stuff looks all right for the most part, but you need to provide @2x.png-style icons (or use vector icons)
  • There's a designer that produces .ui files that automate the most tedious part of UI dev, creating widgets and hooking crap up. You can still do it all by hand (if you want to), there's zero magic here. It's just convenient. This is another codegen step (uic) that generates C++ code.
  • You have full source on all platforms, so crashes are rarely mysteries

Cons

  • QString is UTF-16. It's a legacy choice, and one that I'm sure they regret. So interacting with a lot of UTF-8 sources can be allocate-y. Best practice is to go to QString as soon as possible and then stay there. Use QStringLiteral to avoid dynamic memory allocations for constants (bakes them into .rodata).
  • It does need the MOC to generate bindings for signals and slots. Not a huge deal breaker in practice, but it does take some build system love.
  • There's a ton of crap no one needs for desktop work like Qt Quick, web browser libraries (two of them!), bluetooth and all kinds of other useless junk. Just stick to basic QtWidgets, QtGui, QtConcurrent and QtCore and those are the only thing you need to ship with the binaries. Perhaps QtXML if you're unfortunate enough to have to use XML. It's not a huge dependency at that point IMO compared to what you're getting. There's a deployment tool that makes a custom little side-install of Qt based on just what your app uses which is perfect for shipping of releases.
  • Some of the advanced APIs are complicated to learn and use correctly. Especially implementing QAbstractItemModel from scratch is a rite of passage. (Tip: Use the modeltest code and unit tests.)
  • It's very OO heavy. I'm not a huge fan of OO in general, but it's not too awful for what you get. Basically all real production-quality UIs are an OO paradigm, so whatever. I just accept it as the cost of doing business in the space.

Best practices to consider right off the bat IMO:

  • Use UI files and layouts.
  • Use QRC files for resources.
  • Use QSettings
  • Disable implicit const char* -> QString conversions (compile-time macro)
  • Disable QT legacy keywords (compile-time macro)
  • Use member function connect syntax exclusively and never the SIGNAL(), SLOT() stuff from pre Qt-5. Compile errors are better than runtime errors.
Collaborator

deplinenoise commented Nov 30, 2016

Having used Qt professionally for a while I can definitely recommend it. In my opinion it's the only cross platform toolkit out there that isn't full-on amateur hour. Stuff actually works across different platforms, and it fits in pretty well with other native apps.

Pros

  • Extremely comprehensive. Basically all the things included.
  • Model/view separation is reasonably well done and enables you to focus on (and unit test) data sources - then hook them up to stock views that are pretty solid in terms of features and performance.
  • Documentation (docs, tutorials, examples) are best in class, especially if you consider other open source projects
  • It's reasonably performant if you follow best practices. It certainly smokes anything we ever had running in a browser by a huge margin.
  • Implicit sharing and read only data structures make concurrency an attractive and easy-to-use option for many tasks. We leverage this heavily to kick off tasks to the thread pool and block the UI thread as rarely as possible.
  • Signals and slots are a clean way to connect random stuff together without crazy coupling.
  • Layouts basically solve the "scalable UI" problem
  • Hi-DPI support is basic but workable in Qt 5. Stuff looks all right for the most part, but you need to provide @2x.png-style icons (or use vector icons)
  • There's a designer that produces .ui files that automate the most tedious part of UI dev, creating widgets and hooking crap up. You can still do it all by hand (if you want to), there's zero magic here. It's just convenient. This is another codegen step (uic) that generates C++ code.
  • You have full source on all platforms, so crashes are rarely mysteries

Cons

  • QString is UTF-16. It's a legacy choice, and one that I'm sure they regret. So interacting with a lot of UTF-8 sources can be allocate-y. Best practice is to go to QString as soon as possible and then stay there. Use QStringLiteral to avoid dynamic memory allocations for constants (bakes them into .rodata).
  • It does need the MOC to generate bindings for signals and slots. Not a huge deal breaker in practice, but it does take some build system love.
  • There's a ton of crap no one needs for desktop work like Qt Quick, web browser libraries (two of them!), bluetooth and all kinds of other useless junk. Just stick to basic QtWidgets, QtGui, QtConcurrent and QtCore and those are the only thing you need to ship with the binaries. Perhaps QtXML if you're unfortunate enough to have to use XML. It's not a huge dependency at that point IMO compared to what you're getting. There's a deployment tool that makes a custom little side-install of Qt based on just what your app uses which is perfect for shipping of releases.
  • Some of the advanced APIs are complicated to learn and use correctly. Especially implementing QAbstractItemModel from scratch is a rite of passage. (Tip: Use the modeltest code and unit tests.)
  • It's very OO heavy. I'm not a huge fan of OO in general, but it's not too awful for what you get. Basically all real production-quality UIs are an OO paradigm, so whatever. I just accept it as the cost of doing business in the space.

Best practices to consider right off the bat IMO:

  • Use UI files and layouts.
  • Use QRC files for resources.
  • Use QSettings
  • Disable implicit const char* -> QString conversions (compile-time macro)
  • Disable QT legacy keywords (compile-time macro)
  • Use member function connect syntax exclusively and never the SIGNAL(), SLOT() stuff from pre Qt-5. Compile errors are better than runtime errors.
@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Nov 30, 2016

Owner

Thanks for the write up. Very appreciated.

I guess my biggest issue with Qt is that it's C++ and binding C++ to other languages is lots of work esp given how Qt is working. I honestly really dislike to write code in C++ unless I really have to (at home there is a choice) but given the options here I don't see any other way around it until there are some binding for it.

I really don't think the overhead for an abstraction would be that much. Yes it would be a bunch more indirect calls to functions but that isn't likely a big issue here.

With all that being said I will go for Qt with C++ for now. This will allow me to learn to know the API and implement plugins directly (without having them as proper plugins to begin with) and see how it works out.

Still backends can be written in any language as they are independent from the UI and talk with each other over a message passing like API.

Owner

emoon commented Nov 30, 2016

Thanks for the write up. Very appreciated.

I guess my biggest issue with Qt is that it's C++ and binding C++ to other languages is lots of work esp given how Qt is working. I honestly really dislike to write code in C++ unless I really have to (at home there is a choice) but given the options here I don't see any other way around it until there are some binding for it.

I really don't think the overhead for an abstraction would be that much. Yes it would be a bunch more indirect calls to functions but that isn't likely a big issue here.

With all that being said I will go for Qt with C++ for now. This will allow me to learn to know the API and implement plugins directly (without having them as proper plugins to begin with) and see how it works out.

Still backends can be written in any language as they are independent from the UI and talk with each other over a message passing like API.

@deplinenoise

This comment has been minimized.

Show comment
Hide comment
@deplinenoise

deplinenoise Nov 30, 2016

Collaborator

I really don't think the overhead for an abstraction would be that much. Yes it would be a bunch more indirect calls to functions but that isn't likely a big issue here.

I think the problem is writing and maintaining that wrapper. Have a look at QPainter, and all the surrounding classes you'd need to expose a C API to (QPen, QFont, QBrush, QFontMetrics just to name a few essential ones to get anything done). It's a lot of cost to carry forward for very little value (depending on how much value you place on using Rust of course). Personally I would just write all of this in C++, because at the end of the day you want a usable debugger with a solid UI. I get that Rust is your preference, but it seems to be putting imaginary roadblocks on the path to completing the actual goal: a debugger.

Collaborator

deplinenoise commented Nov 30, 2016

I really don't think the overhead for an abstraction would be that much. Yes it would be a bunch more indirect calls to functions but that isn't likely a big issue here.

I think the problem is writing and maintaining that wrapper. Have a look at QPainter, and all the surrounding classes you'd need to expose a C API to (QPen, QFont, QBrush, QFontMetrics just to name a few essential ones to get anything done). It's a lot of cost to carry forward for very little value (depending on how much value you place on using Rust of course). Personally I would just write all of this in C++, because at the end of the day you want a usable debugger with a solid UI. I get that Rust is your preference, but it seems to be putting imaginary roadblocks on the path to completing the actual goal: a debugger.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Nov 30, 2016

Owner

Point taken. If one really wanted to wrap Qt one would have to auto-generate the wrappings from the C++ headers. Some efforts has been done in this direction like https://github.com/kitech/qt.rs/blob/master/src/gui/qpainter.rs (this isn't actually working or that great generated but shows that it's possible)

So as you suggest I will go with C++. If there (at some point) would be a wrapper that auto-generates the bindings (i.e no manual work) then I will re-consider but now I think C++ is the best option.

Owner

emoon commented Nov 30, 2016

Point taken. If one really wanted to wrap Qt one would have to auto-generate the wrappings from the C++ headers. Some efforts has been done in this direction like https://github.com/kitech/qt.rs/blob/master/src/gui/qpainter.rs (this isn't actually working or that great generated but shows that it's possible)

So as you suggest I will go with C++. If there (at some point) would be a wrapper that auto-generates the bindings (i.e no manual work) then I will re-consider but now I think C++ is the best option.

@emoon

This comment has been minimized.

Show comment
Hide comment
@emoon

emoon Dec 1, 2016

Owner

Code refactoring over to Qt is now being done over here https://github.com/emoon/ProDBG/tree/qt

Thanks everyone for the replies in this thread as it has been really useful.

Owner

emoon commented Dec 1, 2016

Code refactoring over to Qt is now being done over here https://github.com/emoon/ProDBG/tree/qt

Thanks everyone for the replies in this thread as it has been really useful.

@emoon emoon closed this Dec 1, 2016

@emoon emoon referenced this issue Feb 16, 2017

Closed

Readme.md #338

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment