How developers see openSUSE
You probably know that a lot of openSUSE developers are sitting in the SUSE office in Prague, Czech Republic. They are also openSUSE users.
The whole story started by a flame on a mailing list why some of us are not happy with the current state of openSUSE. It turned out there is a lot of different issues. So, we’ve met on a raining winter Friday 3 weeks ago to collect those issues as well as things that people consider to be good about openSUSE.
The result of the hours-long discussion is a list of positive and negative things about openSUSE, very subjective view of the group of developers in Prague. Go, look at the list. There is a lot of problems that I personally see lurking in our community, spelled out loud. The range is wide, from basic community issues to very technical problems that are basically missing features in the distribution.
So, we have collected the feedback. But the question is, what to do with it?
Firstly, I believe the lists are great food for thought. You might not agree with everything, but still, there is some truth in it. At least, those are problems that people consider important enough to try to solve them – encouraging.
Secondly, consider this blog as call for contribution. If you believe some of the areas are really worth improving, get in touch with people listed on the wiki, improve the description in the wiki, propose solutions. One restriction though – please, do not add additional items to the page. We want to keep the ideas where they belong – features eventually to end up in openFate, project-related problems on the mailing lists, …Also, this is not a general list of issues the openSUSE project needs to address. As I’ve written above – the page is a subjective view of a group of people. If you think we need a more general approach, please, bring the idea on openSUSE mailing lists.
Looking forward to your feedback!
Overloading library function
Sometimes during testing (especially while testing maintenance update), I come to a problem how to test the reaction of the program to an unusual function return value (e.g. special error), data, etc. The problem is, that I need to test the unmodified program binary and that it is almost impossible to set up a situation when the error "naturally" occurs.
If the function is in a shared library, there is a simple way to force the program to use another function instead of the one from the library. The program will call the new function, which will return the specific value (unusual error I need to test).
The magic "tool" is LD_PRELOAD variable. When the program is loaded to memory, libraries specified in LD_PRELOAD are loaded before libraries needed by the program. If I have function strdup() in my custom library (loaded by LD_PRELOAD), it will be used instead of strdup() from standard C library.
So for (very simplified) example, let's say I need to test program prog correctly checks whether strdup() returns NULL (I assume that prog segfaults on NULL access): I'll write simple library libexploit which will only contains my new strdup().
exploit.c:
char *strdup(const char *s)
{
return NULL;
}
Makefile:
all: libexploit.so.1.0
clean:
rm -f libexploit.so.1.0 *.o
libexploit.so.1.0: exploit.o
gcc -shared -Wl,-soname,libexploit.so.1 -o libexploit.so.1.0 exploit.o
exploit.o: exploit.c
gcc -Wall -fPIC -c exploit.c
Now when I make the simple library, I'll get result libexploit.so.1.0 which I'll preload to the program:
LD_PRELOAD="`pwd`/libexploit.so.1.0" prog
And it is all - the program got NULL from all calls to strdup().
Simple, right? There is one catch, however. Or two.
First problem is that the original function is replaced by the new one, so you cannot call the original one (not even from your "new" function).
Second problem is that even the original library will start using your function. So if the library is using the overloaded function, it uses the new one. This may result in unexpected library behavior.
Both these problems are not (AFAIK) solvable in a easy way. The only way I've found out so far is the re-factoring of the original library in following steps:
- Rename the original function - e.g. from strdup() to __strdup().
- Replace all calls of function strdup() with calls of function __strdup() in the library source - this will ensure that the library code will always call the correct function.
- Create new function strdup() which will contain the testing code (and can also call the original __strdup() function).
- Compile the library and load it with LD_PRELOAD as described above.
Now, that's finally all.
(This text has also been published on openSUSE wiki)
MonoDevelop 2.0 beta 1
The one I like more is the support for per-project policies. This feature has been planned for long time but other work has been delaying it. Me and Michael Hutchinson had a chance to talk quite a lot about it while I was at Boston a couple of months ago. The policies model allows setting properties at global, solution, folder and project levels. Settings such as tab width can be defined in any of those levels and will cascade down to the lower levels (where it can be overriden if required). Many settings are already available in this way, and many more will be in future releases.

Another new feature, or rather improvement, is the support for multiple frameworks. MD already had support for targeting the 1.1/2.0 CLR for quite a long time, but did not have the concept of 'target framework', which is more generic. For example, .NET 3.0 is based on the 2.0 CLR and it just includes some additional assemblies. What complicates things a bit is that Mono does not follow the .NET releases, so for example Mono 2.0 includes bits from all .NET versions. To simplify all this and to be compatible with MSBuild, it is now possible to select the target .NET framework, which includes 1.1, 2.0, 2.1 (Silverlight), 3.0 and 3.5. The project system is fully aware of the chosen target framework, so for example it won't let you reference a 3.5 project from a 3.0 project.
The source editor keeps improving in many ways. Mike Krueger has spent quite a lot of time fixing issues in code completion, which now works in many more contexts. My contribution on code completion (besides stabilization work in the parser database) is support for completion of generic types with constraints. For example, in the following class code completion is showing the Dispose method because there is a constraint forcing the generic argument to implement it:

There are other improvements, such as the new Go to File dialog I blogged about some time ago, better support for completion in ASP.NET projects, and fixes in the GTK# designer. There is still a lot of work to do, but we are getting close to 2.0.
Object Oriented UI for YaST
After my last blog I worked on YaST (what a surprise) and didn't have any time to post anything until now.
Meanwhile I read some chapters from the "Thinking in Java" book. There are some chapters about OOP in general and it brings me to idea, how it would be great in YaST. As a side effect it also means get away from ycp ;-). Thanks to UI independence I can use Python with the YaST UI.
Here's some code example:
widget_library.py:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import yui
class MainDialog:
def __init__(self):
self.factory = yui.YUI.widgetFactory()
self.dialog = self.factory.createMainDialog()
def __del__(self):
self.dialog.destroy()
class Popup:
def __init__(self):
self.factory = yui.YUI.widgetFactory()
self.dialog = self.factory.createPopupDialog()
def __del__(self):
self.dialog.destroy()
class TableDialog:
def __init__(self, d):
self.f = d.factory
vbox1 =self.f.createVBox( d.dialog )
self.f.createVStretch(vbox1)
hbox1 =self.f.createHBox( vbox1 )
self.f.createHStretch(hbox1)
self.f.createHSpacing(hbox1,1)
vbox2 =self.f.createVBox( hbox1 )
self.Table( vbox2 )
vspace =self.f.createVSpacing(vbox1,2)
self.f.createHSpacing(hbox1,1)
self.f.createHStretch(hbox1)
self.f.createVStretch(vbox1)
etype=-1
while etype!=5:
event = d.dialog.waitForEvent()
etype = event.eventType()
self.HandleEvent( event )
print etype
def Table(self,parent):
vbox3 =self.f.createVBox( parent )
self.customWidget(vbox3)
theader = yui.YTableHeader()
theader.addColumn("Targets")
self.table =self.f.createTable( vbox3, theader )
hbox2 =self.f.createHBox( vbox3 )
self.pbAdd =self.f.createPushButton( hbox2, "&Add" )
self.pbEdit =self.f.createPushButton( hbox2, "&Edit" )
self.pbDel =self.f.createPushButton( hbox2, "&Delete")
self.enableDisableButtons()
def customWidget(self,parent):
pass
def HandleEvent(self,event):
if (event.widget()==self.pbAdd):
self.handleAdd(event)
elif (event.widget()==self.pbEdit):
self.handleEdit(event)
elif (event.widget()==self.pbDel):
self.handleDel(event)
self.enableDisableButtons()
def enableDisableButtons(self):
self.pbEdit.setEnabled(self.table.itemsCount()>0)
self.pbDel.setEnabled(self.table.itemsCount()>0)
main.py:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import yui
from widget_library import *
class TargetDialog(TableDialog):
def __init__(self,d):
TableDialog.__init__(self,d)
def customWidget(self,parent):
hbox =self.f.createHBox( parent )
self.f.createInputField(hbox, "Target")
self.f.createInputField(hbox, "Identifier")
def handleAdd(self, event):
print "add target item"
def handleEdit(self,event):
print "edit target item ..."
def handleDel(self,event):
print "delete target item ..."
class MyTable(TableDialog):
def __init__(self,d):
TableDialog.__init__(self,d)
def handleAdd(self,event):
print "adding ..."
TargetDialog(Popup())
def handleEdit(self,event):
print "edit item ..."
def handleDel(self,event):
print "delete item ..."
if __name__== "__main__":
td = TargetDialog(MainDialog())
I know that code is not nice and not very useful, but here's some nice OOP examples:
inheritance, composition, etc ...
Easily put into constructor, what kind of dialog I want:
TableDialog(MainDialog()) or TargetDialog(Popup())
Inherit some class and override methods you want (see MyTable.handle*())
This is much better than generate file from template (as we do now).
I like this way and I'll keep working on it during my ITO.
Bye,
Michal
Moving on...
sonjakrauseharder. See you there!
Tomboy 0.13.5 Brings a Better Windows Installation Experience
From http://live.gnome.org/Tomboy/Installing/Windows :
Instructions for installing a Tomboy Windows release
Upgrading from Tomboy 0.13.4 or earlier
- Uninstall Tomboy.
- Uninstall any existing versions of gtk-sharp you may have installed.
- Continue with Installation instructions.
- Install Novell's gtk-sharp 2.12.8 or newer.
- Restart.
- Run Tomboy installer 0.13.5 or newer.
- Enjoy!
- On your Linux box, copy all of the *.note files out of ~/.tomboy .
- On your Windows box, quit Tomboy.
- On your Windows box, copy all the *.note files from Linux into %APPDATA%\tomboy .
Thanks so much to Mike Kestner for working his ass off (on his own time) updating the gtk-sharp installers, making them easier to develop and build, and fixing the issues reported by Tomboy users. Apps like Tomboy, Banshee, and GNOME Do would simply not exist without all of his hard work.
More r6xx mysteries
It really took a long night (and approx. a hundred reboots) to find this:
When you want to
- change VGT_INDX_OFFSET / VGT_MIN_VTX_INDX / VGT_MAX_VTX_INDX or
- switch to a different shader
Today in the office I found out that this is only necessary on my laptop's M72, on RV610, on RV630, and on RV635 - but not on RV670 or RV770. So this is chipset specific, but not VC releated...
What - as I assume - happens is that only a write to the render target registers stalls writing to the VGT and shader registers, so this seems to be some kind of flaw in the pipelining logic on some of the chips. As setting the render target again doesn't have a too big performance impact, I assume it's best to do it regardless of the chipset.
Latest and greatest(untested)?!
- 2.6.24 on January 24th 2008,
- 2.6.26 on July 13th, 2008, and
-
2.6.27 on October 9 2008
Here is when it reached the users
- Gentoo 2008.0 released on July 6, 2008 has linux 2.6.24 which was ~5.5 months old.
- Ubuntu 8.10 released on October 30th, 2008 has 2.6.27 which was ~0.6 months old.
- Fedora 10 released on 25 November 2008 has 2.6.27 which was ~1.5 months old.
- Opensuse 11.1 released on December 18th, 2008, has 2.6.27 wihch was roughly ~2.3 months old.
- Debian 5.0 released on February 14th, 2009 has 2.6.26 which was roughly ~7 months old.
Distros used by power-users seems to be always running slightly older version compared to the distros aimed at the layman! Yeah, but power users^Wdevelopers use the unstable/development/factory/head version of their favourite distro and not the released stable. But Ubuntu stable(!) is based on debian unstable! And debian stable is so outdated. opensuse seems to be quiet the latest but not straight from the unstable development snapshot.
p.s: I use only opensuse regularly among these distros. So any mis-information and bias is likely. ;)
Install more packages? ["Yes"]["No"]
It was the same with YaST package manager and pop-up question from the title of this post. I'm sure we all remember that one:
It was introduced in openSUSE 10.1 (aka BrokenSwManagement edition) in order to alleviate suffering of the poor users forced to use our package management (powered by zmd and baby-libzypp) with ultra-slow start-up. libzypp grew faster and faster over the time, but the pop-up question remained and (quite reasonably) it started to annoy users. "Why do I have to click to have this crappy pop-up disappear?" they asked. "I've made my choice, installed all packages I wanted, so I want to answer no further questions."
After many heated discussions, we finally made the pop-up go away in openSUSE 11.1 After clicking on 'Accept' and installing all packages, package manager simply ended. That, of course, made the other half of the users speak up: "Why YaST does not ask anymore whether I want to install more packages? I don't want to start package manager anew each time. I simply want to have an option to install something more I forgot about in the first round."
In openSUSE 11.2, my colleague lslezak (now the link to his blog should be here, but he is too shy to have one :)) used really ingenious way of cutting the Gordian knot - he made the behaviour on exit from package manager configurable. And not only that - besides an option to close package manager (for those who want to be done with it) and option to restart it (for those who may want to come back and select something more), he added a third one. When the package installation is over, you can choose to display a neat summary of what has been installed/deleted, how long did it take and view some detailed logs. Then, you can either finish, or go back to install more packages:
Now all you have to do is to open /etc/sysconfig/yast2 file in your favourite editor and set PKGMGR_ACTION_AT_EXIT variable to some reasonable value. Please find more detailed information here.
"But I don't want to edit some cryptic file manually," you might think. "Isn't there any other way?" Well, of course there is. YaST ncurses package manager has a brand new menu that allows you to pick the exit action of your choice in a few key presses:
There are some minor things left to polish, but it basically works by now. Better don't ask me how the sysconfig variable is actually written :-) It took me by surprise to realize that libzypp's interface to sysconfig is read-only, so I'm impatienly waiting for Augeas ;-)
Riding the D-Bus with Ruby
Riding the D-Bus with Ruby
The last time I looked at D-Bus is a couple of years ago. What I saw back then was promising in technology but ugly in (C-)programming. D-Bus has come a long way 'til then.And so have my programming skills with scripting languages, esp. with Ruby. The ruby-dbus project provides a nice and easy-to-use programming API, once one has mastered the lack of examples and the D-Bus nomenclature.
About D-Bus
There is plenty of information available on D-Bus. I personally found the Introduction to D-Bus most valuable from a developers point of view.
D-Bus originates from the freedesktop.org initiative and is hosted at www.freedesktop.org
Basically, D-Bus is a RPC (remote procedure call) mechanism, allowing different programs to talk to each other and provide services in a standardized way.
The transport used for talking is called a bus, meaning everyone can ride (connect to) it. Usually there are two independent buses available
- System bus
This is for system-wide services, like hardware information (usually provided by HAL) - Session bus
This is for per-login services, like a Gnome Desktop session.
The nice thing about D-Bus is that it allows introspection. You can ask a service about its capabilities. And the D-Bus itself is a service, so you just need to know about org.freedesktop.DBus to find all other services.
Services provide objects. These are organized in a tree-like fashion and typically addressed using slash-separated paths, just like filenames. Iterating over the objects of org.freedesktop.Hal gives you all devices.
Objects then have members. Members are methods to call, providing the functionality of the service. To make things more
Putting it all together gives you this chain
Bus (System/Session)
-> Service (e.g. org.freedesktop.Hal)
-> Object (e.g. /org/freedesktop/Hal/devices/storage_model_DVDRW_LH_20A1S)
-> Interface (e.g. org.freedesktop.Hal.Device.Storage.Removable)
-> Member (e.g. bool CheckForMedia())
Using ruby-dbus
Connecting to the bus in Ruby is as easy asrequire 'dbus' bus = DBus::SystemBus.instance # resp. 'bus = DBus::SessionBus.instance'DBus::SystemBus is a Singleton, hence the .instance instead of the usual .new for creating the object.
Now you can create a proxy object. Its named 'proxy' because the real object lives on the other side of the connection, in the service. The proxy object is in your application and proxy-ing calls via D-Bus to the service object. You can use this to find all services on the bus
require 'dbus'
bus = DBus::SystemBus.instance
bus.proxy.ListNames[0].each do |service|
puts "Service: #{service}"
end
Given a known service, D-Bus introspection allows to find its objects, subnodes and interfaces
require 'dbus'
bus = DBus::SystemBus.instance
# Create the proxy object
proxy = bus.introspect "org.freedesktop.Hal", "/"
# proxy.bus gives you the bus
# proxy.path is the object path
# proxy.destination is the service name
# Print object interfaces
proxy.interfaces.each do |interface|
puts "Object #{proxy.path} provides #{interface}"
end
# Print object subnodes
proxy.subnodes.each do |path|
puts "-> #{proxy.path}/#{path}"
end
A specific interface of an object can be accessed by the [] operator. And the interface knows about the signature of its methods.
require 'dbus'
bus = DBus::SystemBus.instance
# create proxy for the 'computer' device
proxy = bus.introspect "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer"
# Print object interfaces
proxy.interfaces.each do |interface|
puts "Object #{proxy.path} provides #{interface}"
proxy[interface].methods.each do |key,value|
puts " #{value.rets} #{key}( #{value.params} )"
end
end
Due to the dynamic nature of Ruby, Object methods are directly accessible in normal Ruby conventions. One just has to select the right interface first.
require 'dbus'
bus = DBus::SystemBus.instance
proxy = bus.introspect "org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer"
iface = proxy["org.freedesktop.Hal.Device.CPUFreq"]
freq = iface.GetCPUFreqPerformance
gov = iface.GetCPUFreqGovernor
puts "Frequency #{freq}, Governor #{gov}"
Riding the D-Bus with Ruby is easy and fun !