Question

I've been having an issue with segmentation faults when accessing a class variable (an array of Qt::Actions), and I've been trying to whittle it down to a minimal code example that replicates the issue:

#!/usr/bin/ruby

require 'Qt4'
require 'rufus/scheduler'

app = Qt::Application.new(ARGV)

class ManagerWidget < Qt::Widget
    signals 'changed(int)'

    def initialize
        super(nil)

        max_index = 2
        next_index = 0

        scheduler = Rufus::Scheduler.start_new
        scheduler.every '10s' do
            emit changed(next_index)
            if next_index < max_index - 1
                next_index += 1
            else
                next_index = 0
            end
        end
    end
end

class Tray < Qt::Widget
    def initialize
        super(nil)

        tray = Qt::SystemTrayIcon.new
        manager_widget = ManagerWidget.new
        menu = Qt::Menu.new

        tray_icon = Qt::Icon.new("./icons/Gnome-Preferences-Desktop-Wallpaper-64.png")

        actions = []
        manager_widget.connect(SIGNAL('changed(int)')) do |i|
            puts "changed #{i}"
            actions[i].text = '...' if actions && actions[i]
        end

        2.times do |i|
            sub_menu = Qt::Menu.new("#{i + 1}")
            actions[i] = sub_menu.add_action('x')
            menu.add_menu(sub_menu)
        end

        tray.icon = tray_icon
        tray.context_menu = menu

        tray.show
    end
end

Tray.new
app.exec

The above code outputs:

"sni-qt/12147" WARN  14:35:48.326 void StatusNotifierItemFactory::connectToSnw() Invalid interface to SNW_SERVICE 
changed 0
changed 1
changed 0
changed 1
changed 0
changed 1
changed 0
changed 1
./min-code-example.rb:42: [BUG] Segmentation fault
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
[... snipped due to character limits on posting ...]
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Aborted (core dumped)
Failed (134)

It seems to be necessary to use the sub-menus to trigger this issue - at least adding the actions to the tray menu itself runs for quite a while with no issue (I left it for more than 10 times as long as it took to get the error with the above code).

Ruby version: ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]

Qt version: 4.8.1

Bindings version: qtbindings (4.8.3.0)

Linux version: Ubuntu 12.04

Another odd behaviour is that the output from the puts call is sometimes displayed in the console immediately, other times it only prints once I mouse over the tray icon.

I'm not even sure where to start when it comes to tracking this down, so any input you have is much appreciated.

Update: I've left this for a while since I couldn't get any further. I've tried to start over with this but I'm still coming across the same problem. I've delved a little deeper in to the problem and since it said 'missing_method' I started by printing the class to make sure I was definitely looking at a Qt::Action (I am), and then which methods are available according to actions[0].methods.

.methods output:

[:setShortcut, :shortcut=, :qobject_cast, :inspect, :pretty_print, :className,
:class_name, :inherits, :findChildren, :find_children, :findChild, :find_child,
:connect, :method_missing, :const_missing, :dispose, :isDisposed, :disposed?,
:qVariantValue, :qVariantFromValue, :**, :+, :~, :-@, :-, :*, :/, :%, :>>,
:<<, :&, :^, :|, :<, :<=, :>, :>=, :==, :is_a?, :kind_of?, :methods,
:protected_methods, :public_methods, :singleton_methods, :qDebug, :qFatal,
:qWarning, :SIGNAL, :SLOT, :emit, :QT_TR_NOOP, :QT_TRANSLATE_NOOP, :nil?, :===,
:=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup,
:initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust,
:untrusted?, :trust, :freeze, :frozen?, :to_s, :private_methods,
:instance_variables, :instance_variable_get, :instance_variable_set,
:instance_variable_defined?, :instance_of?, :tap, :send, :public_send,
:respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method,
:define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=,
:instance_eval, :instance_exec, :__send__, :__id__, "blockSignals", "children",
"connect", "deleteLater", "disconnect", "dumpObjectInfo", "dumpObjectTree",
"dynamicPropertyNames", "event", "eventFilter", "inherits", "installEventFilter",
"widgetType?", "killTimer", "metaObject", "moveToThread", "objectName", "parent",
"property", "qt_metacall", "qt_metacast", "removeEventFilter", "objectName=",
"parent=", "setProperty", "setUserData", "signalsBlocked", "startTimer",
"thread", "userData", "actionGroup", "activate", "associatedGraphicsWidgets",
"associatedWidgets", "autoRepeat", "data", "font", "hover", "icon", "iconText",
"checkable?", "checked?", "enabled?", "iconVisibleInMenu?", "separator?",
"visible?", "menu", "menuRole", "parentWidget", "priority", "actionGroup=",
"autoRepeat=", "checkable=", "checked=", "data=", "disabled=", "enabled=",
"font=", "icon=", "iconText=", "iconVisibleInMenu=", "menu=", "menuRole=",
"priority=", "separator=", "shortcut=", "shortcutContext=", "shortcuts=",
"softKeyRole=", "statusTip=", "text=", "toolTip=", "visible=", "whatsThis=",
"shortcut", "shortcutContext", "shortcuts", "showStatusText", "softKeyRole",
"statusTip", "text", "toggle", "toolTip", "trigger", "whatsThis"]

In this case I was trying to do actions[0].enabled = true when the segmentation fault occurred, which is in the output as far as I understand it (6th line from the bottom, enabled=). I also tried setEnabled(true), set_enabled(true) and just about anything I could think of.

Even calling inspect on the action object is causing a segmentation fault, though doing this inside the loop that initially places the actions in the array is fine. I really don't get where this is going wrong.

Edit: In response to the suggestion to use QTimer instead I've attempted this and I'm still getting the same problem. The code is currently a fair bit more complicated than what is listed above, so I'll write some quick pseudo-code here to illustrate the flow:

def init_tray
    actions = []
    2.times do |i|
        actions[i] = ... # init and add to systray, store reference in array
    end
    update = Proc.new do |i|
        actions[i].setText('...') # update the text on one of the actions defined above
    end
    listener = ... # create a listener that can be called by Manager on certain events - will call the update Proc among other things.
    manager = Manager.new(..., listener)
end

The call to Manager.new initialises that object and at the end calls the listener with a state change, this in turn calls the update Proc, which accesses the actions array. This should all be in the same thread at this stage, none of these lines depend on QT apart from the actual creation of the Qt::Action. I've removed the Rufus scheduling and replaced it with QTimer, but it simply isn't getting far enough for that to be the issue.

Was it helpful?

Solution 2

I've spent far too long on this without being able to work out why this is happening (thanks to those that have tried to help, but it has unfortunately not solved the issue). As such, I'm placing my work-around here as an answer in case someone else has a similar issue:

I've done away with the array, instead wrapping the code that was to use it in a Proc that I create inside the loop that was previously populating the array. Since a Proc created within this loop has direct access to the variable in question, there is no longer any need to store it in an array and retrieve it later. It brought up one or two issues of it's own since the code in the Proc is now executed once per action per SIGNAL rather than having one code block going through all relevant actions, but they were significantly easier to handle.

OTHER TIPS

One thing that I don't see that you've tried is using a newer revision of ruby. p0 seems to potentially be rife with problems.

Ruby 1.9.3-p392 is the latest version of 1.9.3.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top