The GtkSourceView library has this handy concept of a GtkSourceGutterRenderer. They are similar in concept to a GtkCellRenderer but for the gutter to the left or right of the text editor.
Like a GtkCellRenderer, you pack it into a container and they are placed one after another with some amount of optional spacing in-between. This is convenient because you can start quickly by mixing and matching what you need from existing components. Those include text (such as line numbers), pixbuf rendering, or even code folding regions.
However, there is a cost to this sort of composition. One is function call overhead, but that isn’t particularly interesting to me because there are ways to amortize that away (like we did with the pixel cache). The real problem is one of physical space. Each time a renderer is added, the width of the gutter is increased.
Builder 3.26.0 added a new column for breakpoints, and so we increased our width by another 18 pixels or so. Enough to be cumbersome. It looked like the following which has 4 renderers displayed.
Line changes (git)
Once you reach some level of complexity, you need to bite the bullet and implement a single renderer that has all the features you want in one place. It allows you to overlap content for density and use the background itself as a component. We just did that for Builder and here is what it looks like.
There are a couple other nice points performance-wise by implementing the gutter as a single renderer. We can take a number of “shortcuts” in the render path that a generic renderer cannot without sacrificing flexibility. Since the gutter is not pixel cached, this has improved the performance of kinetic scrolling on various HiDPI displays. There is always more performance work to do, but I’m rather happy with the result so far.
You’ll find this in the upcoming 3.26.1 release of Builder and is already available in Builder’s Nightly flatpak.
Like every year, GUADEC has snuck up on me. I’ll be heading out to Manchester in a handful of days which means things are going to get hectic any moment now.
We just reached another milestone in our development phase towards 3.26. I’ve landed two important components which will have important roles in Builder’s future. The new visual layout, and the new shortcut engine. Neither are complete yet, but they are good enough to land on master and allow us to iterate without giant branches.
The new layout is based upon a design iteration lead by Allan which Andreas, Jakub, and myself took part. Not everything is implemented but the parts which most heavily contribute to user workflow are in place.
The new shortcut engine has also landed. This is a monumental amount of work because it completely overhauls the keyboard input model within Builder. We’ve moved to a “capture and bubble” event delivery for keyboard input so that we have more flexibility in how shortcuts are activated.
The event delivery is in one of three phases. Capture, Dispatch, or Bubble. The capture phase allows the widget hierarchy (starting from the toplevel) to handle an input event before the destination widget. Dispatch is delivery to the expected destination, where GtkBindingSets are activated. Finally, the bubble phase allows the hierarchy to handle the event if nothing handled it previously.
This also includes a whole swath of features around it for user-modifiable shortcut themes, custom keyboard controllers, a shortcut editor and more. To simplify the process of merging into Builder it has a compatibility interface to support CSS-based -gtk-key-bindings properties.
Effectively, bubble/capture allows us to have keyboard shortcuts that only activate if the source editor or terminal have not stolen the input. A convincing Vim implementation for our source editor can really benefit from this.
I’ve been aggressively pushing forward our new layout branch to integrate the new design work we’ve been iterating on. I don’t think we need to have it all done to merge to master, so we are rapidly approaching the time-frame for the branch to land.
There is much from the design still missing, but every day more pieces come together. I expect to have a good portion of it done by GUADEC.
A lot happened this week on the wip/chergert/layout branch. Here are some highlights.
Georges landed a “focus mode” fullscreen mode for Builder.
We’ve landed a patch in flatpak-builder to update terminal titles. This will allow us to scrape that info via the PTY in Builder for better progress messages.
Document titlebars now match the primary-color of the content. We also fade between states. This took some craftiness to avoid cascading the entire CSS tree. Video example below.
DzlPropertiesGroup is a convenient GActionGroup implementation for exporting multiple object properties from a GObject. This is more convenient than GPropertyAction when you are exposing lots of properties together.
The TODO plugin was ported to C and employs various techniques to use reduce memory overhead.
Dazzle gained convenience API to do insertion sort on a GtkListStore in O(log n) time by accessing the GSequence directly. This should be a safe layer-violation on Gtk+ 3.x.
Terminal, Devhelp, and HTML-Preview were ported to the new layout design.
IdeSymbolResolver gained a “find nearest scope” API which is used to update the scope name in the document titlebar. Both C and Vala are supported. Other languages need an implementation still.
The project tree was tweaked to look more like the mockup. While this won’t be our default project-tree for 3.26, we will keep it around and therefore it should match the design.
Overview map was ported to the new layout design.
Plugins should use the new IdeBuffer::change-settled API to be notified of when they should update their state based on buffer content (unless alternate API is provided via the plugin interface).
We’ve added type icons to the devhelp search that match the language-feature icons used elsewhere in Builder.
Scrolling to the insertion point on buffer load has been vastly improved.
Performance of buffer loading has also improved.
Todo and build diagnostics have been ported to the new design.
You can do some pretty evil things with GtkTreeView if you put your mind to it. One of the most common questions over the years has been how to reflow (wrap) text. The short answer is you can’t. The answer for those willing to hack around it is something like:
So the real question is “Why not use GtkListBox?”
GtkListBox is a fantastic widget. But there are some things it does not deal well with today. I presume that once it can deal with only keeping a minimum number of widgets in memory (and the size-request magic that goes with it) it would be a better solution.
Builder keeps a lot of widgets active during the lifetime of the application, and that makes style propagation particularly slow. The fewer widgets we can use, the more responsive we can keep things. (And of course, there are multiple ways to do this).
Features that the UI redesign depends on have landed in libdazzle. This includes animated widget transitions and more.
Builder’s Flatpak of Stable and Nightly channels now bundle OSTree 2017.7 and Flatpak 0.9.6 which should improve situations where we were failing to load summary files from the host.
A painful bug where Builder (Nightly Flatpak channel) would crash when launched from the Activities menu was fixed. This was a race condition that seemed to not happen when run from the command line. After some manual debugging the issue was fixed.
To simplify future debugging, we’ve added a “Bug Buddy” like feature. If you remember bug-buddy, you’re old like me. If Builder receives a SIGSEGV, we try to fork()/exec() an instance of gdb to inspect our process. It will dump a lot of useful information for us like where files are mapped in memory, instruction pointer addresses, and any callstack that can be discovered.
Libdazzle gained some new action muxer helpers to clean up action visibility.
The new editor (perspective, grid, columns, and view) design will help us drastically simplify some of Builder’s code. But this also needs forward-porting a bunch of plugins to the new design.
The new libdazzle based menu joiner landed to help us integrate contextual menus based on file content-type as GMenu does not support “conditionals” when displaying menus.
meson test should work again for running Builder’s unit tests under the Meson build system.
Anoop blogged about his work to add a code indexer to Builder here.
Lucie blogged about her work to make documentation easily accessible while you code here.
Umang blogged about his work to improve our word completion engine here.
You can do some pretty flashy things with Dazzle. Tonight I added the missing pieces to be able to make widgets look like they transition between parents.
The following is a video of moving a GtkTextView from one GtkStack to another and flying between those containers. Compare this to GtkStack transitions that can only transition between their children, not their ancestors. Fun!
There really is a lot of code in libdazzle already. So occasionally it makes sense to spotlight some things you might be interested in using.
Today, while working on various Builder redesigns, I got frustrated with a common downfall of GAction as used in Gtk applications. Say you have a UI split up into two sections: A Header Bar and Content Area. Very typical of a window. But it’s also very typical of an editor where you have the code editor below widgetry describing and performing actions on that view.
The way the GtkActionMuxer works is by following the widget hierarchy to resolve GActions. Since the HeaderBar is a sibling to the content area (and not a direct ancestor) you cannot activate those actions. It would be nice for the muxer to gain more complex support, but until then… Dazzle.
It does what most of us do already, copy the action groups between widgets so they can be activated.
// my_countainer should be either your headerbar or parent of it
// my_view is your view containing the attached action groups
// the mux key is used to remove old action groups
"a mux key");
Exciting, I know.
The number of times I’ve been asked if Gtk has a GtkPaned that can have multiple handles is pretty high. So last year, while working on Builder’s panel engine, I made one. It also gained some new features this week as part of our Builder redesign.
It knows how to handle minimum sizes, natural sizes, expanding, dragging, and lots of other tricky bits. There are lots of really annoying bits about GtkPaned from it’s early days that make it a pain when dealing with window resizes. MultiPaned tries to address many of those and do the right thing by default.
It should be strictly a step up from using GtkPaned of GtkPaned of GtkPaned.