Explicit drawing

I’m currently updating an old plugin I wrote for 0.6

That plugin uses a custom widget subclass I designed with a ::draw(NVGcontext) method

Now I’m seeing my plugin appear but not the custom widget being drawn.

Does 2.3 call widgets custom drawing the same way as the older versions? Or is there a new way to do this?

You should take a look at the API docs for changes to methods you are using from 0.6: VCV Rack API: rack::widget::Widget Struct Reference

Alternatively just go snooping through the GitHubs of some of the open source free plugins, for example:


1 Like


So I’ve been looking at examples, but it’s still not clear the path by which VCVRack is calling into my plugin.

I’ve changed my code to

void SlowSliderWidget::draw(const rack::widget::Widget::DrawArgs& args) {

    NVGcontext* vg = args.vg;


    nvgFillColor(vg, nvgRGBA(0,0,66,255));
    nvgRoundedRect(vg, ssm.getRect().left(), ssm.getRect().top(), ssm.getRect().width(), ssm.getRect().height(), 6);



Which compiles OK. But there’s still no sign of this function running. Is Rack automatically calling this draw function for my widget when the widget is attached to a ModuleWidget?

My module contains the code

    SlowSliderWidget *ssw;
    ssw= createParamCentered<SlowSliderWidget>(Vec(10,30), module, SlowSliders::SLOW1_PARAM);

Which I think should be making my SlowSliderWidget and attaching it to the parent correctly.

But there’s no sign of it appearing.

The code looks ok, but its difficult to know without the whole context, is your source open to look at anywhere?

Trying to understand your code: your module is SlowSliders and you are trying to add a param with a custom widget? But you are creating the param as a SlowSliderWidget, which would be the module widget, not a custom param widget?

Here is a basic example of how i would add a custom widget to a module, its the MyCustomWidget that the param uses, not the MyModuleWidget

struct MyModuleWidget : rack::app::ModuleWidget
  MyCustomWidget *cw;

  MyModuleWidget(MyModule *module)
    cw = rack::createParamCentered<MyCustomWidget>(
      rack::math::Vec(10.0f, 10.0f), module, MyModule::PARAM_ID);
1 Like

I’ve updated my code with some INFO statements, and I can see that while this code that creates the is being run, the

SlowSliderWidget::draw(const rack::widget::Widget::DrawArgs& args) 

is never being called.

Thanks for this. I’ll see if I can make my code more like yours.

This was all written 4 years ago, so the conventions in VCV have probably changed since then.

Will report back shortly

So what’s missing in my code is


I’m guessing this is a new requirement?

When I add that line, it immediately takes down Rack with a segmentation fault. :sob:

[1.844 info src/SlowSlider.cpp:34 setup] Here in SlowSliderWidget::setup 0.000000,0.000000
[1.844 info adapters/standalone.cpp:265 main] Running window
[1.851 info src/window/Svg.cpp:28 loadFile] Loaded SVG /media/phil/151848002EC71722/TOOLS/music_making_tools/linux/Rack2Free/res/ComponentLibrary/Rail.svg
[1.852 fatal adapters/standalone.cpp:49 fatalSignalHandler] Fatal signal 11. Stack trace:
17: ./Rack() [0x4042ed]
16: /lib/x86_64-linux-gnu/libc.so.6(+0x42520)
15: ./libRack.so(rack::app::ParamWidget::step()+0x1a)
14: ./libRack.so(rack::widget::Widget::step()+0x36)
13: ./libRack.so(rack::widget::Widget::step()+0x36)
12: ./libRack.so(rack::widget::Widget::step()+0x36)
11: ./libRack.so(rack::widget::Widget::step()+0x36)
10: ./libRack.so(rack::widget::Widget::step()+0x36)
9: ./libRack.so(rack::widget::Widget::step()+0x36)
8: ./libRack.so(rack::ui::ScrollWidget::step()+0x13)
7: ./libRack.so(rack::app::RackScrollWidget::step()+0x36f)
6: ./libRack.so(rack::widget::Widget::step()+0x36)
5: ./libRack.so(rack::window::Window::step()+0x591)
4: ./libRack.so(rack::window::Window::run()+0x28)
3: ./Rack(main+0xe75)
2: /lib/x86_64-linux-gnu/libc.so.6(+0x29d90)
1: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)
0: ./Rack() [0x404219]

What I’m suspecting is that somewhere in the chain of constructors something isn’t actually getting constructed / allocated properly. But I wasn’t previously seeing it because my custom widget was never properly registered within the module. Now it is, the parent is sending it messages which are blowing it up.

module is NULL when your plugin is shown in the browser, so your code will need to account for that, and draw an appropriate preview. I’m betting your code has an unguarded dereference of module.

1 Like

That sounds pretty plausible.

Am I right in thinking that Rack creates an instance of the ModuleWidget when rendering the thumbnails to be picked from? But NOT the module inside?

The issue is I’m trapping the onButton event in one of my widgets.

  void SlowSliderWidget::onButton(const rack::widget::Widget::ButtonEvent &e) {
     INFO("SlowSliderWidget::onButton:: ///////////////////////////////////////////////");
     setDestination(e.pos.x, e.pos.y);

And the crash seems to happen when I go to select that thumbnail.

So I’m wondering if by clicking on the thumbnail I’m triggering this onButton event, which is, in turn, trying to access the module behind the scenes?

I don’t see anything I’m doing directly to do that, but is there a way of protecting against it?

Because actually my stack trace is now

[44.527 fatal adapters/standalone.cpp:49 fatalSignalHandler] Fatal signal 11. Stack trace:
20: ./Rack() [0x4042ed]
19: /lib/x86_64-linux-gnu/libc.so.6(+0x42520)
18: ./libRack.so(rack::engine::Engine::moduleToJson(rack::engine::Module*)+0x2c)
17: ./libRack.so(rack::history::ModuleAdd::setModule(rack::app::ModuleWidget*)+0x66)
16: ./libRack.so(+0x376e7b)
15: ./libRack.so(rack::app::browser::ModelBox::onButton(rack::widget::Widget::ButtonEvent const&)+0x2a9)
14: ./libRack.so(rack::widget::Widget::onButton(rack::widget::Widget::ButtonEvent const&)+0xed)
13: ./libRack.so(rack::widget::Widget::onButton(rack::widget::Widget::ButtonEvent const&)+0xed)
12: ./libRack.so(rack::widget::Widget::onButton(rack::widget::Widget::ButtonEvent const&)+0xed)
11: ./libRack.so(rack::ui::ScrollWidget::onButton(rack::widget::Widget::ButtonEvent const&)+0x103)
10: ./libRack.so(rack::app::browser::Browser::onButton(rack::widget::Widget::ButtonEvent const&)+0xfd)
9: ./libRack.so(rack::ui::MenuOverlay::onButton(rack::widget::Widget::ButtonEvent const&)+0x11d)
8: ./libRack.so(rack::widget::OpaqueWidget::onButton(rack::widget::Widget::ButtonEvent const&)+0x105)
7: ./libRack.so(rack::widget::EventState::handleButton(rack::math::Vec, int, int, int)+0x269)
6: ./libRack.so(_glfwPollEventsX11+0xfdf)
5: ./libRack.so(rack::window::Window::step()+0x84)
4: ./libRack.so(rack::window::Window::run()+0x28)
3: ./Rack(main+0xe75)
2: /lib/x86_64-linux-gnu/libc.so.6(+0x29d90)
1: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)
0: ./Rack() [0x404219]

which features several button events. (Although not mine. The INFO in my function is not appearing in the log).

Also the moduleToJson seems to come out of nowhere. Is that a method my module is meant to implement?

Yes, that is correct. If you reference module within your ModuleWidget, you’ll need to check for null first otherwise the module browser will crash.

This page has some handy info: VCV Manual - Migrating v1 Plugins to v2. Especially the Potential runtime bugs section.

wasn’t that also true in v 1.0? I remember that a lot, and I never ported any of those modules to 2, must have been 1.

That’s quite possible.

Every time I open this thread I expect something a lot ruder…


haha - took me a while to get that one. Well played.