Whisker Menu 1.5.0 released!

Yesterday I released a new Whisker Menu, version 1.5.0, which includes the most frequently requested feature: the ability to change the background opacity of the menu. Of course, if you use xfwm4 as your window manager that will remove the drop shadow, but otherwise the feature works nicely.

Another feature added in this release was the inclusion of a small profile picture next to the username. You can set what program is launched to edit your profile when you click it; by default it tries to run the program mugshot.

I also made some changes to make it easier to use. If you add an item to the desktop from the right-click menu it will be made executable by default, so that you can launch it without prompting. Also, when you have the menu hierarchy shown, you can now click on the folders to expand them instead of having to click on the arrows next to the folder names. And finally, you can adjust the amount of recent items shown in the menu if you want more than 10.

In related news, Whisker Menu has become an official Xfce project! You can fetch the release tarballs from archive.xfce.org and the current source from git.xfce.org. It is also now part of the Xfce bug database, so I have closed the GitHub issues.

Enjoy! And, of course, please report any bugs you find.

Whisker Menu 1.3.0 released!

I have just released a new version of Whisker Menu, version 1.3.0. The biggest feature in this release is probably the addition of search actions, which are inspired by the Xfce application finder’s custom actions. These are useful if you want to perform specific actions by typing something into the search field, and included by default are four example actions that you can change or remove. For instance, one of the default actions allows you to open your default web browser and search Wikipedia by starting your search with “!w” (eg, “!wopen source” will show you Wikipedia’s definition of “Open Source”).

This release also has a lot of smaller features, such as the ability to run arbitrary programs from your path by typing the entire program name into the search field. You can also now drag menu items to your panel or desktop if you do not want to use the context menu. Additionally there is more flexibility in configuring the command buttons, as well as the option to hide them if you do not need them. You can also hide the category or menu item icons by setting their size to “None” if you prefer a menu without icons.

I hope you enjoy this release! And, of course, please let me know if you have any issues.

Theming Whisker Menu

I have seen several people state that Whisker Menu does not use their GTK theme. This is understandable but completely incorrect. Whisker Menu is a regular window and therefore it matches the GTK theme of regular windows. It can not be a GtkMenu because of the widgets it uses (believe me, I tried), so it does not match the theming of menus.

I did investigate if it would be possible for Whisker Menu to “pick up” the theming of GTK menus and mimic them. Short answer: no. Longer answer: haha, my sanity is worth more than the creaky mess of hacks it would take, and besides I’m fairly certain it still wouldn’t work. So instead I did something much simpler: I named the menu widget itself “whiskermenu-window” so users or theme makers can play with its appearance as much as they want.

I will not be adding any theme configuration settings to Whisker Menu. First, I really have no interest in doing so. Second, modifying the theme from a .gtkrc file gives you much more power than I could ever expose from a GUI. Third, anything I add would probably interfere with .gtkrc theming.

So, how do you theme Whisker Menu? It’s pretty easy, actually. Open up the hidden file named .gtkrc-2.0 in your home directory with any text editor you want. If the file doesn’t exist, create it. Now, if you want to change the background color of the menu window add something like this:

style "darkback"
{
	bg[NORMAL] = "#404040"
	bg[ACTIVE] = "#606060"
	bg[PRELIGHT] = "#808080"
}
widget "whiskermenu-window*" style "darkback"


Whisker Menu darkback

If you want to change the window text color as well, add something like this:

style "darkback"
{
	bg[NORMAL] = "#404040"
	bg[ACTIVE] = "#606060"
	bg[PRELIGHT] = "#808080"
	fg[NORMAL] = "#ccc"
	fg[ACTIVE] = "#fff"
	fg[PRELIGHT] = "#fff"
}
widget "whiskermenu-window*" style "darkback"


Whisker Menu darkback2

If you want to change the background color of the menu items, add something like this:

style "darktree"
{
	base[NORMAL] = "#404040"
	base[ACTIVE] = "#606060"
}
widget "whiskermenu-window*TreeView*" style "darktree"


Whisker Menu darktree

If you want to change the text color of the menu items as well, add something like this:

style "darktree"
{
	base[NORMAL] = "#404040"
	base[ACTIVE] = "#606060"
	text[NORMAL] = "#ccc"
	text[ACTIVE] = "#fff"
}
widget "whiskermenu-window*TreeView*" style "darktree"


Whisker Menu darktree2

These examples just scratch the surface of what you can do with theming from a .gktrc file. I don’t have much experience with it myself, nor do I intend to really look into it further. There are plenty of resources on how to make GTK themes and what they say should be applicable to Whisker Menu as well.

Revisiting signal handlers

Ever since I changed how I handle connecting GTK+ signals to C++ members I have never been completely happy with that code. I prefer to not repeat myself, and I like the power and simplicity that templates can bring (and the safety they have over macros). I though that any GCC before 4.7 would not allow me to write the signal handlers the way I want, but it turns out I was wrong!

Based on the load time error of Whisker Menu 1.0.0 I had surmised that there was a bug in GCC where you can’t take the address of a template function becuase it did not handle the name mangling properly. However, upon further research I discovered that the bug really is that if you take the address of a template function and cast it to something else before storing it the template is not instantiated. Easy enough to fix: just create a function pointer of the correct type and then cast that:

template <typename T, typename R, typename A1, typename A2>
gulong g_signal_connect_slot(gpointer instance,
        const gchar* detailed_signal,
        R (T::*member)(A1,A2),
        T* obj,
        bool after = false)
{
    class Slot
    {
        T* m_instance;
        R (T::*m_member)(A1,A2);

    public:
        Slot(T* instance, R (T::*member)(A1,A2)) :
            m_instance(instance),
            m_member(member)
        {
        }

        static R invoke(A1 a1, A2 a2, Slot* slot)
        {
            return (slot->m_instance->*slot->m_member)(a1, a2);
        }

        static void destroy(Slot* slot)
        {
            delete slot;
        }
    };
    R (*invoke_slot)(A1,A2,Slot*) = &Slot::invoke;
    void (*destroy_slot)(Slot*) = &Slot::destroy;

    return g_signal_connect_data(instance,
            detailed_signal,
            reinterpret_cast<GCallback>(invoke_slot),
            new Slot(obj, member),
            reinterpret_cast<GClosureNotify>(destroy_slot),
            after ? G_CONNECT_AFTER : GConnectFlags(0));
}

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

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

The code is not quite as simple as the original version, though, because variadic templates are only available in C++11. Instead I have to make make overloads of the function for each amount of parameters I want to support. I did clean it up in other ways by using local classes, which I think makes the new template slot handlers more clear. It even compiles to less space than using class functions for slots.

Whisker Menu will be staying with Xfce

I’m sorry to disappoint the users who have been requesting this, but after giving it some serious consideration I have decided that I will not be porting Whisker Menu to any other desktop environment. I set out to make a menu for Xfce, and Whisker Menu relies on Xfce quite a lot throughout the codebase. I would have to redesign Whisker Menu to try and support different environments, and even then I would still have to completely rewrite it for some of them as they are Qt based and very little code could be shared between them. Again, sorry, but Whisker Menu will remain Xfce only.

A new Whisker Menu release

I have released version 1.2.0 of Whisker Menu. This release contains several smaller but commonly requested features. For those users who wanted subcategories you can now enable loading the menu hierarchy, which will show each category as a tree instead of a flat list. You can also tweak the layout of the menu to be similar to Windows by placing the search entry next to the panel button. Additionally, you can also choose which commands are run when you press the “All Settings”, “Lock Screen”, and “Log Out” buttons. Enjoy!

Whisker Menu 1.1.0 released!

I have made a new stable release of Whisker Menu, version 1.1.0. This release includes the three most commonly requested features: the ability to show the menu from an external command (which allows for showing the menu from a keyboard shortcut), the ability to have text on the panel button, and finally the ability to switch the categories by hovering for a small time over the category buttons instead of having to click on them.

Another big feature in this release is that I rewrote the search algorithm inspired by that of the Synapse semantic launcher. Whisker Menu will now also search for words and each character instead of just finding exact matches of the text you typed. This allows you to type “ff” and find both LibreOffice and Firefox. The search results are also now sorted by relevance to make it easier to find what you are looking for. And finally, it now also searches the names of the executables (so you can for example find GNOME’s Document Viewer by searching for “evince”, as that is the program’s name).

I hope you enjoy this update to the menu! As always, please let me know if you have any issues.

Go, little menu!

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!

More internal changes to Whisker Menu

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.

Internal changes to Whisker Menu

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.