[Kde-bindings] error running korundum/rubylib/examples/dcop/dcopsignal.rb

Richard Dale Richard_Dale at tipitina.demon.co.uk
Wed Jun 8 06:38:23 UTC 2005


On Wednesday 08 June 2005 03:52, Chris Gow wrote:
> Hello:
>
> I'm attempting to run the dcopsignal.rb example but I am getting the
> following error:
>
> $ ./dcopsignal.rb:16:in `testEmitSignal': undefined method `fullSignalName'
> for KDE::Internal:Module (NoMethodError)
>         from ./dcopsignal.rb:16:in `doit'
>         from /usr/lib/site_ruby/1.8/Qt/qtruby.rb:1023:in `qt_invoke'
>         from /usr/lib/site_ruby/1.8/Qt/qtruby.rb:1023:in `method_missing'
>         from /usr/lib/site_ruby/1.8/Qt/qtruby.rb:1023:in `exec'
>         from /usr/lib/site_ruby/1.8/KDE/korundum.rb:406:in `exec'
>         from ./dcopsignal.rb:26
> Mutex destroy failure: Device or resource busy
>
> My kdebinding packages didn't come with the examples, so I downloaded the
> 3.4.1 kdebinding source from download.kde.org and extracted the examples
> from it.
>
> Any idea what's wrong? Do I have something incorrect on my system?
Oops, yes it doesn't work for me either. I've fixed it in the svn. Please find 
the corrected version of korundum.rb attached and try that.

-- Richard
-------------- next part --------------
=begin
/***************************************************************************
                          Korundum.rb  -  KDE specific ruby runtime, dcop etc.
                             -------------------
    begin                : Sun Sep 28 2003
    copyright            : (C) 2003-2004 by Richard Dale
    email                : Richard_Dale at tipitina.demon.co.uk
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
=end

module KDE
	DCOPMeta = {}

	# An entry for each dcop signal or slot
	# Example 
	#  int foobar(QString,bool)
	#  :name is 'foobar'
	#  :full_name is 'foobar(QString,bool)'
	#  :arg_types is 'QString,bool'
	#  :reply_type is 'int'
	DCOPMember = Struct.new :name, :full_name, :arg_types, :reply_type
	
	# If the class with the 'k_dcop' slots declaration is not a subclass of DCOPObject,
	# then 'dcop_object' holds a instance of DCOPObject for the class to use as a
	# proxy. For subclasses of DCOPObject, 'dcop_object' will always be nil
	class DCOPMetaInfo
		attr_accessor :dcop_object, :changed
		attr_reader :k_dcop_signals, :k_dcop
		
		def initialize(aClass)
			DCOPMeta[aClass.name] = self
			@dcop_object = nil
			@k_dcop_signals = {}
			@k_dcop = {}
			@changed = false
		end
		
		def add_signals(signal_list)
			signal_list.each do |signal|
				signal = DCOPClient.normalizeFunctionSignature(signal)
				if signal =~ /^([\w,<>:]*)\s+([^\s]*)\((.*)\)/
					args = DCOPClient.normalizeFunctionSignature($3)
					@k_dcop_signals[$2] = DCOPMember.new($2, $2 + "(" + args + ")", args, $1)
				else
					qWarning( "Invalid DCOP signal format: '#{signal}'" )
				end
			end
		end
		
		def add_slots(slot_list)
			slot_list.each do |slot|
				if slot =~ /^([\w,<>:]*)\s+([^\s]*)\((.*)\)/
					args = DCOPClient.normalizeFunctionSignature($3)
					@k_dcop[$2] = DCOPMember.new($2, $1 + ' ' + $2 + "(" + args + ")", args, $1)
				else
					qWarning( "Invalid DCOP slot format: '#{slot}'" )
				end
			end
		end
	end # DCOPMetaInfo

	def KDE.hasDCOPSignals(aClass)
		classname = aClass.name if aClass.is_a? Module
		meta = DCOPMeta[classname]
		return !meta.nil? && meta.k_dcop_signals.length > 0
	end

	def KDE.hasDCOPSlots(aClass)
		classname = aClass.name if aClass.is_a? Module
		meta = DCOPMeta[classname]
		return !meta.nil? && meta.k_dcop.length > 0
	end

	def KDE.getDCOPSignalNames(aClass)
		classname = aClass.name if aClass.is_a? Module
		signals = DCOPMeta[classname].k_dcop_signals
		return signals.keys
	end

	module Internal
		def Internal.fullSignalName(instance, signalName)
			classname = instance.class.name if instance.class.is_a? Module
			signals = DCOPMeta[classname].k_dcop_signals
			return signals[signalName].full_name
		end
	end

	class KDE::DCOPObject
		def initialize(*k)
			super
		end

		def process(fun, data, replyType, replyData)
			if fun == 'functions()' or fun == 'interfaces()'
				return super
			end
			
			slots = DCOPMeta[@client.class.name].k_dcop
			dcop_slot = slots[fun.sub(/\(.*/, '')]
			if dcop_slot.nil?
				# Can't find an entry for the slot being called? This shouldn't happen..
				return false
			end
			
			replyType << dcop_slot.reply_type
			KDE::dcop_process(	@client, 
								dcop_slot.name, 
								Qt::Internal::getMocArguments(fun), 
								data,
								replyType, 
								(replyType == 'void' or replyType == 'ASYNC') ? nil : Qt::Internal::getMocArguments(replyType), 
								replyData )
		end

		def interfaces()
			ifaces = super()
			return ifaces << @client.class.name
		end

		def functions()
			funcs = super()
			return funcs + @functions
		end
		
		def functions=(funcs)
			@functions = funcs
		end
		
		# If a ruby class has 'k_dcop' slots declarations, but isn't a 
		# subclass of DCOPObject, then keep an instance of it
		def client=(obj)
			@client = obj
		end
		
		def inspect
			str = super
			if @functions != nil
				str.sub(/>$/, " objId=%s, functions=Array (%d element(s))>" % [objId.inspect, functions.length])
			end
		end
		
		def pretty_print(pp)
			str = to_s
			if @functions != nil
				pp.text str.sub(/>$/, "\n objId=%s,\n functions=Array (%d element(s))>" % [objId.inspect, functions.length])
			end
		end
	end

	# If a class contains a k_dcop slots list declaration, then create a DCOPObject
	# associated with it	
	def KDE.createDCOPObject(instance)
		meta = DCOPMeta[instance.class.name]
		return nil if meta.nil?

		if meta.dcop_object.nil? or meta.changed
			funcs = []
			meta.k_dcop.each_value do |value| 
				sig = value.reply_type + ' ' + value.name + '(' + value.arg_types + ')'
				funcs << sig 
			end
			meta.changed = false
			if instance.kind_of? DCOPObject
				instance.functions = funcs
				instance.client = instance
				return nil
			else
				if meta.dcop_object.nil?
					# Only ever allocate a single instance of a DCOPObject if the
					# class isn't a subclass of DCOPObject
					meta.dcop_object = DCOPObject.new(instance.class.name)
					meta.dcop_object.client = instance
				end
				meta.dcop_object.functions = funcs
			end
		end

		return meta.dcop_object
	end
	
	class DCOPRef < Qt::Base
		def method_missing(*k)
			# Enables DCOPRef calls to be made like this:
			#
			# dcopRef = DCOPRef.new("dcopslot", "MyWidget")
			# result = dcopRef.getPoint("Hello from dcopcall")
			begin
				# First look for a method in the Smoke runtime.
				# If not found, then throw an exception and try dcop.
				super(*k)
			rescue
				dcopArgs = k[1, k.length-1]
				dcopArgs <<  NoEventLoop << -1
				method = k[0].id2name
				# Make 'parrot.age = 7' a synonym for 'parrot.setAge(7)'
				method = 'set' + method[0,1].upcase + method[1,method.length].sub("=", "") if method =~ /.*[^-+%\/|]=$/
				
				# If the method name contains underscores, convert to camel case
				while method =~ /([^_]*)_(.)(.*)/ 
					method = $1 + $2.upcase + $3
				end
				
				# Get the functions() for this dcop ref and 
				# cache method_name => full_type_signature in a hash
				if @functions.nil?
					@functions = {}
					funcs = call("functions()")
					if funcs.nil?
						return nil
					end
					funcs.each do |func|
						if func =~ /^([\w,<>:]*)\s+(.*)(\(.*\))/
							return_type = $1
							name = $2
							args = $3
							if args =~ / /
								# Remove any arg names
								args.gsub!(/ \w*/, "")
							end
							
							# Make thing? a synonym for isThing() or hasThing()
							if name =~ /^(is|has)(.)(.*)/
								predicate = $2.downcase + $3 + '?'
								if @functions[predicate].nil?
									@functions[predicate] = return_type + " " + name + args
								end
							end
							
							if @functions[name].nil?
								@functions[name] = return_type + " " + name + args
							else
								# If a function name is overloaded, just keep a single name entry in
								# the hash, not all the full type signatures. Then leave dcopTypeNames() 
								# to try and resolve the ambiguous call from the ruby arg types passed.
								@functions.delete(name)
								@functions[name] = name
							end
						end
					end
				end
				
				method = @functions[method]
				if method.nil?
					qWarning( "DCOPRef: call #{k[0].id2name}() not found" )
					return
				end

				return callExt(method, *dcopArgs)
			end
		end
		
		def dcopTypeNames(*k)
			typeNames = "("
			k.each do |arg|
				if arg.kind_of? Integer
					typeNames << "int,"
				elsif arg.kind_of? Float
					typeNames << "double,"
				elsif arg.kind_of? Array
					typeNames << "QStringList,"
				elsif arg.kind_of? String
					typeNames << "QString,"
				elsif arg.kind_of? Qt::Base
					typeNames << arg.class.name + ","
				elsif arg.instance_of? FalseClass or arg.instance_of? TrueClass
					typeNames << "bool,"
				end
			end
			typeNames.sub!(/,$/, '')
			typeNames.gsub!(/Qt::/, 'Q')
			typeNames.gsub!(/KDE::/, 'K')
			typeNames << ")"
			return typeNames
		end
		
		def call(fun, *k)
			k << NoEventLoop << -1
			callExt(fun, *k)
		end

		def callExt(fun, *k)
			if isNull
				qWarning( "DCOPRef: call #{fun} on null reference error" )
				return
			end
			sig = fun
			if fun.index('(') == nil
				sig << dcopTypeNames(*k[0, k.length - 2])
			end
			dc = dcopClient()
			if !dc || !dc.isAttached
				qWarning( "DCOPRef::call():  no DCOP client or client not attached error" )
				return
			end
			if sig =~ /([^\s]*)(\(.*\))/
				full_name = $1+$2
			else
				qWarning( "DCOPRef: call #{fun} invalid format, expecting '<function_name>(<args>)'" )
				return
			end
			return KDE::dcop_call(	self, 
									full_name, 
									Qt::Internal::getMocArguments(full_name),
									*k )
		end

		def send(fun, *k)
			if isNull
				qWarning( "DCOPRef: send #{fun} on null reference error" )
			end
			sig = fun
			if fun.index('(') == nil
				sig << dcopTypeNames(*k)
			end
			dc = dcopClient()
			if !dc || !dc.isAttached
				qWarning( "DCOPRef::send():  no DCOP client or client not attached error" )
				return
			end
			if !sig =~ /^([^\s]*)(\(.*\))/
				qWarning( "DCOPRef: send #{sig} invalid format, expecting '<function_name>(<args>)'" )
				return
			end
			return KDE::dcop_send(	self, 
									fun, 
									Qt::Internal::getMocArguments(sig),
									*k )
		end

		def methods
			if @functions.nil?
				functions()
			end

			result = super + @functions.keys.map {|k| k.sub(/^(set)([A-Z])(.*)/) { $2.downcase + $3 + '=' } }
			return result.uniq
		end

		def inspect
			str = super
			str.sub(/>$/, " app=%s, obj=%s>" % [app.inspect, obj.inspect])
		end
		
		def pretty_print(pp)
			str = to_s
			pp.text str.sub(/>$/, "\n app=%s,\n obj=%s>" % [app.inspect, obj.inspect])
		end
	end
	
	def CmdLineArgs::init(*k)
		if k.length > 0 and k[0].kind_of?(Array)
			# If init() is passed an array as the first argument, assume it's ARGV.
			# Then convert to a pair of args 'ARGV.length+1, [$0]+ARGV'
			array = k.shift
			super(*([array.length+1] + [[$0] + array] + k))
		else
			super
		end
	end
	
	# A sane alternative to the strange looking C++ template version,
	# this takes a variable number of ruby args as classes to restore
	def MainWindow::kRestoreMainWindows(*k)
		n = 1
		while MainWindow.canBeRestored(n)
			className = MainWindow.classNameOfToplevel(n)
			k.each do |klass|
				if klass.name == className
					klass.new.restore(n)
				end
			end
			n += 1
		end
	end
	
	class Application
		def initialize(*k)
			super
			$kapp = self
		end
		
		# Delete the underlying C++ instance after exec returns
		# Otherwise, rb_gc_call_finalizer_at_exit() can delete
		# stuff that KDE::Application still needs for its cleanup.
		def exec
			super
			self.dispose
			Qt::Internal.application_terminated = true
		end
	end
	
	class UniqueApplication
		def initialize(*k)
			super
			$kapp = self
		end
		
		def exec
			super
			self.dispose
			Qt::Internal.application_terminated = true
		end
	end
	
	class AboutData
		def inspect
			str = super
			str.sub!(/>$/, " appName=%s, copyrightStatement=%s, programName=%s, version=%s, shortDescription=%s, homepage=%s, bugAddress=%s>" %
							[appName.inspect, copyrightStatement.inspect, programName.inspect, version.inspect,
							shortDescription.inspect, homepage.inspect, bugAddress.inspect] )
			length = authors.length
			if length > 0
				str.sub!(/>$/, ", authors=Array (%d element(s))>" % length)
			end
			length = credits.length
			if length > 0
				str.sub!(/>$/, ", credits=Array (%d element(s))>" % length)
			end
			length = translators.length
			if length > 0
				str.sub!(/>$/, ", translators=Array (%d element(s))>" % length)
			end
			return str
		end
		
		def pretty_print(pp)
			str = to_s
			str.sub!(/>$/, "\n appName=%s,\n copyrightStatement=%s,\n programName=%s,\n version=%s,\n shortDescription=%s,\n homepage=%s,\n bugAddress=%s>" % 
							[appName.inspect, copyrightStatement.inspect, programName.inspect, version.inspect,
							shortDescription.inspect, homepage.inspect, bugAddress.inspect] )
			length = authors.length
			if length > 0
				str.sub!(/>$/, ",\n authors=Array (%d element(s))>" % length)
			end
			length = credits.length
			if length > 0
				str.sub!(/>$/, ",\n credits=Array (%d element(s))>" % length)
			end
			length = translators.length
			if length > 0
				str.sub!(/>$/, ",\n translators=Array (%d element(s))>" % length)
			end
			pp.text str
		end
	end
	
	class AboutPerson
		def inspect
			str = super
			str.sub(/>$/, " emailAddress=%s, name=%s, task=%s, webAddress=%s>" % 
						[emailAddress.inspect, name.inspect, task.inspect, webAddress.inspect] )
		end
		
		def pretty_print(pp)
			str = to_s
			pp.text str.sub(/>$/, "\n emailAddress=%s,\n name=%s,\n task=%s,\n webAddress=%s>" % 
						[emailAddress.inspect, name.inspect, task.inspect, webAddress.inspect] )
		end
	end
	
	class AboutTranslator
		def inspect
			str = super
			str.sub(/>$/, " emailAddress=%s, name=%s>" % 
						[emailAddress.inspect, name.inspect] )
		end
		
		def pretty_print(pp)
			str = to_s
			pp.text str.sub(/>$/, "\n emailAddress=%s,\n name=%s>" % 
						[emailAddress.inspect, name.inspect] )
		end
	end
	
	class Service
		def inspect
			str = super
			str.sub(/>$/, " library=%s, type=%s, name=%s>" % [library.inspect, type.inspect, name.inspect])
		end
		
		def pretty_print(pp)
			str = to_s
			pp.text str.sub(/>$/, "\n library=%s,\n type=%s,\n name=%s>" % [library.inspect, type.inspect, name.inspect])
		end
	end
	
	class URL
		def inspect
			str = super
			str.sub(/>$/, " url=%s, protocol=%s, host=%s, port=%d>" % [url.inspect, protocol.inspect, host.inspect, port])
		end
		
		def pretty_print(pp)
			str = to_s
			pp.text str.sub(/>$/, "\n url=%s,\n protocol=%s,\n host=%s,\n port=%d>" % [url.inspect, protocol.inspect, host.inspect, port])
		end
	end
end

class Object
	def RESTORE(klass)
		n = 1
		while MainWindow.canBeRestored(n)
			klass.new.restore(n)
			n += 1
		end
	end

	def I18N_NOOP(x) x end
	def I18N_NOOP2(comment, x) x end
end

class Module
	def k_dcop_signals(*signal_list)
		meta = KDE::DCOPMeta[self.name] || KDE::DCOPMetaInfo.new(self)
		meta.add_signals(signal_list)
		meta.changed = true
	end

	def k_dcop(*slot_list)
		meta = KDE::DCOPMeta[self.name] || KDE::DCOPMetaInfo.new(self)
		meta.add_slots(slot_list)
		meta.changed = true
	end
end


More information about the Kde-bindings mailing list