Search code examples
c++gtk3gnomegtkmm

Get gnome-3-like windows with custom headerbar


My Problem

I'm working with Anjuta/gtkmm/C++ and want to design a program that looks similar to other gnome 3 programs.

This includes that big draggable Headerbar with custom buttons on it and other visual effects like the bigger background shadow behind the window.

Black Bar Issue

So far I discovered the GtkHeaderBar Widget. I also discovered that you can use main_win->set_titlebar(*header_bar); to make it draggable. Furthermore I ticked the "Client side window decorations" check box in the glade plugin (inside Anjuta).

However now it looks like in the image below. How do I get rid of that black bar?

Compatibility with other Desktops

Another question is how to maintain compatibility with other DEs? My bet would be to have two different glade/xml files (or one part of it in two external files). One contains the code that generates the gnome-3-like window and one that generates a normal one. When loading the program it is decided which file should be loaded based on the fact whether it is running under gnome 3 or any other desktop environment. But what is the best way to determine if the DE is gnome 3?

screenshot with black bar on top

Update

When I untick "Client side window decorations" and "Decorated" the black bar is gone. But the shadows and the rounded corners are also gone.

enter image description here

Is the way I'm doing this even the right one? How should it be done?


Solution

  • Okay, I figured it out.

    Black bar issue

    To get this cool gnome bar in glade without having one of the aforementioned issues follow these steps:

    1. Tick "Client side window decorations" in the "General tab" in the window properties. Make sure that "Decorated" is ticked, too, even if it is greyed out. You can tick (or untick) it while "Client side window decorations" is unticked.

    enter image description here

    1. A new space at the top of the window should appear

    enter image description here

    1. Place a header bar inside it

    enter image description here

    1. (Optionally) Tick "Show window controls" in the "General" tab of its properties and give it a title and a subtitle

    enter image description here

    Voila:

    enter image description here

    Note that something like main_win->set_titlebar(*header_bar); isn't even needed. There's nothing specific that you have to do in your code to make this work.

    Compatibility

    It seems the only way to maintain compatibility is the way already described in the question post. The best way to determine if gnome-shell is running or if the right version of GTK+ is used is the one below. (Or at least the best one I came up with). It uses the function exec from here: stackoverflow.

    //is gnome-shell running?
    std::string gnomeString = exec(
        "pgrep -lx \"gnome-shell\" | head -1 | cut -d \" \" -f2"
    );
    //get version string
    std::string gnomeVersionString = exec(
        "gnome-shell --version | sed -e \"s/GNOME Shell //\""
    );
    
    //parse version string to int array; not 100% necessary, but nice to have
    std::vector<int> gnomeVersion;
    std::stringstream ss(gnomeVersionString); std::string item;
    
    while (std::getline(ss, item, '.'))
        gnomeVersion.push_back(std::atoi(item.c_str()));
    
    //optional requirement for gnome-like header bar:
    bool isGnome3 = gnomeString == "gnome-shell\n" &&
                    gnomeVersion.size() > 0 &&
                    gnomeVersion[0] >= 3;
    
    //absolute requirement for gnome-like header bar:
    bool correctGTKversion = gtk_major_version >= 3 &&
                             gtk_minor_version >= 10;
    
    std::cout << "isGnome3: " << (isGnome3?"yes":"no") << "\n";
    std::cout << "correctGTK+: " << (correctGTKversion?"yes":"no") << "\n";
    std::cout << "gnome version: ";
    for(int v : gnomeVersion)
        std::cout << v << ".";
    std::cout << "\n";