Category: Whisker Menu (Page 8 of 8)

Go, little menu!

Posted on July 19, 2013, under Whisker Menu

16 comments

I am really excited and pleased with how popular Whisker Menu is turning out to be! It has already been added to some Linux distros, and both Manjaro and the Xfce edition of Linux Mint have made it the default menu! That is amazing, and I still can’t believe it. Thank you to all of those who have spread the word, reported bugs, and submitted translations!

One of the things I had not given a second thought to when writing Whisker Menu was my use of C++11. The new standard makes C++ much cleaner, and any Linux distro that has Xfce 4.8 or 4.10 mostly likely also has a version of GCC at least as recent as 4.6 (which is the earliest version of GCC that can compile the bits of C++11 I used).

However, not everybody is using Linux. There are a lot of BSD users out there who don’t yet have LLVM/Clang, and so in an effort to make my menu usable by as many people as possible I have downgraded to C++98. Some of the things I will miss most from C++11 are rvalue references (no more passing objects by const reference! yay!), range-based for, and the repurposed auto keyword:

C++11:

LauncherModel example(std::map<std::string, Launcher*> sorted_items)
{
	LauncherModel model;
	for (auto i : sorted_items)
	{
		model.append_item(i.second);
	}
	return model;
}

C++98:

void example(const std::map<std::string, Launcher*>& sorted_items, LauncherModel& model)
{
	for (std::map<std::string, Launcher*>::const_iterator i = sorted_items.begin(), end = sorted_items.end(); i != end; ++i)
	{
		model.append_item(i->second);
	}
}

For those who have never seen the new C++11 constructs, auto is a variable whose type is determined at compile time. That makes the code for dealing with STL iterators a lot cleaner. The range-based for is also nice for reducing code, and it even works with anything that provides begin() and end() functions!

Another change I have made is how I handle the signal callbacks. I had previously decided to use macros to hook up the GTK+ signals to C++ classes. However, I have since found the obfuscation of what is really going on to be frustrating at times. Because of that I have taken the macros out and replaced them with what they were actually doing, even if it does bloat the header files somewhat.

When I wrote Whisker Menu I was viewing it as a pet project. I wasn’t planning to share it, and once I decided to make it public I was not expecting that many people to use it. However, I was very much mistaken about how many people would like to try it out, and this is going to require me to reconsider some assumptions I made when writing it!

There is one thing I have changed already. I had come up with a simple hack to get GTK+ signals to connect to C++ member functions by using variadic templates to generate functions that could be called by C. I was quite pleased with how straightforward it was:

template <typename T, typename R, typename... Args>
struct SlotArgs
{
	T* instance;
	R (T::*member)(Args...);
};

template <typename T, typename R, typename... Args>
R invoke_slot_args(Args... args, SlotArgs<T,R,Args...>* slot)
{
	return (slot->instance->*slot->member)(args...);
}

template <typename T, typename R, typename... Args>
void delete_slot_args(SlotArgs<T,R,Args...>* slot)
{
	delete slot;
}

template<typename T, typename R, typename... Args>
gulong g_signal_connect_slot(gpointer signal_obj, const gchar* detailed_signal, R (T::*member)(Args...), T* instance)
{
	return g_signal_connect_data(signal_obj, detailed_signal,
		(GCallback)&invoke_slot_args<T,R,Args...>,
		new SlotArgs<T,R,Args...>{instance, member},
		(GClosureNotify)&delete_slot_args<T,R,Args...>,
		GConnectFlags(0));
}

class Example
{
public:
	Example();
	gboolean on_button_press_event(GtkWidget* widget, GdkEventButton* event);
};

Example::Example()
{
	g_signal_connect_slot(widget, "button-press-event", &Test::on_button_press_event, this);
}

This works because the calling convention between C and C++ on Linux is the same by default and the only thing you have to worry about is name mangling. I tested it on both GCC and Clang, and it worked perfectly. On my very up-to-date Arch system, that is. Cue dramatic music. 😛 So of course there is a bug in GCC 4.6 and earlier where it does not properly handle the name mangling of template functions. Oops! I have rewritten things to use macros and static member functions instead:

#define SLOT_CALLBACK(klassmember) G_CALLBACK(klassmember ## _slot)

#define SLOT_2(R, klass, member, A1, A2) \
	static R member ## _slot(A1 arg1, A2 arg2, klass* obj) \
		{ return obj->member(arg1, arg2); } \
	R member(A1 arg1, A2 arg2)

class Example
{
public:
	Example();
	SLOT_2(gboolean, Test, on_button_press_event, GtkWidget*, GdkEventButton*);
};

Example::Example()
{
	g_signal_connect(widget, "button-press-event", SLOT_CALLBACK(Test::on_button_press_event), this);
}

It is not as easy to read, though, because instead of having actual member functions in the header file they are generated by a macro. And it does require a different macro for each number of arguments I want to support. Still, it works out to be the same thing in the end, and it does have the potential to be slightly more efficient.

Obviously, I could write out the code generated by the macro, but that would get repetitive and boring quite fast. And then if I want to change a function’s signature I would have to make sure to update both functions to match. Annoying! So, macros it is.

Announcing Whisker Menu

Posted on June 20, 2013, under Whisker Menu

8 comments

I have just released a brand new project named Whisker Menu. It will only appeal to some of my users as the project is for Linux and other UNIX-like OSs, but I thought I would share it anyway. I have made an alternate menu for Xfce inspired by other menus like KDE’s Kickoff. I have been using it as my main menu for the past month or so and I have found it to be quite comfortable.

The menu shows you a list of favorite applications when you open it. You can configure what goes in the list, and how they are ordered. It also has a list of the ten programs most recently launched from the menu. Along the side is a series buttons for top-level categories that allow you to quickly browse all of you installed applications.

Whisker Menu

This is the first time I have ever used GTK+ in a program, and it will probably be the only time I do so. I do not like it (to put it mildly), and I do not understand how anybody could possibly prefer it to Qt. Still, it was necessary to write a native Xfce panel plugin. However, I did use C++11 instead of straight C, because there is a limit to how much I am willing to torture myself. 😛

Categories