Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set the hover background color of a Gtk3 MenuItem

Tags:

python

css

gtk3

I have a tray icon with a popup menu. I am trying to set the background color of the menu items in this popup. I am able to set the text color but not the background color of the menu item.

enter image description here

The background that appears is the default Ubuntu orange, and I can't override it.

I've created a sample application that demonstrates this problem. Just copy-paste it into a .py file and it should run.

from gi.repository import Gtk, Gdk
import sys

class TrayIcon:

    def __init__(self):
        self.statusicon = Gtk.StatusIcon()
        self.statusicon.set_from_stock(Gtk.STOCK_MEDIA_PLAY)
        self.statusicon.connect("popup-menu", self.OnShowPopupMenu)
        window = Gtk.Window()

    def OnShowPopupMenu(self, icon, button, time):
       menu = Gtk.Menu()
       first = self.GetMenuItem("First")
       second = self.GetMenuItem("Second")
       menu.append(first)
       menu.append(second)
       menu.show_all()
       menu.popup(None, None, lambda w,x: self.statusicon.position_menu(menu, self.statusicon), self.statusicon, 3, time)

    def GetMenuItem(self, txt):
    menuItem = Gtk.MenuItem(txt)

    screen = Gdk.Screen.get_default()
    css_provider = Gtk.CssProvider()
    #css_provider.load_from_data("GtkWidget { color:white; background-color: green; } GtkWidget:hover,GtkWidget:selected { color:white; background-color:pink;}")
    css_provider.load_from_data("GtkMenuItem { color:#0f0; background-color: #f00; } GtkMenuItem:hover,GtkMenuItem:selected { color:#00f; background-color:#f00; font-weight:bold;}")
    context = Gtk.StyleContext()
    context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    menuItem.connect("button_press_event", self.exit)

    return menuItem

    def exit(self, a,b):
    sys.exit()

TrayIcon()
Gtk.main()

For GtkMenuItem the normal background and :hover background are being ignored. For GtkWidget the :hover background is being ignored. My aim is to prevent that Ubuntu orange from showing up without disabling the menu item.

Is there a way to set the background and hover/mouseover color of a GtkMenuItem? (without using 'import gtk')

I am using Ubuntu 12.04, default theme.

Edit1: To add a bit of clarity, this is what I am trying to do, but without 'import gtk'.

    #Prevent background color when mouse hovers
    style = menuItem.get_style().copy()
    style.bg[gtk.STATE_SELECTED] = style.bg[gtk.STATE_NORMAL]
    menuItem.set_style(style)

Edit2: I've also tried override_background_color() and modify_bg, and again, the orange still shows up on hover. Here are variants of what I have tried.

    menuItem.override_background_color(Gtk.StateFlags.NORMAL,Gdk.RGBA(1.0,0.0,0.0,1))
    menuItem.modify_bg(Gtk.StateFlags.NORMAL,Gdk.color_parse("red"))
    menuItem.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(1.0, 1.0, 1.0, 1.0))
    menuItem.override_background_color(Gtk.StateFlags.SELECTED, Gdk.RGBA(1.0, 1.0, 1.0, 1.0))
    menuItem.override_background_color(Gtk.StateFlags.FOCUSED, Gdk.RGBA(1.0, 1.0, 1.0, 1.0))

Edit3: Answer has been provided, see this post.

like image 709
Mendhak Avatar asked Jul 08 '12 07:07

Mendhak


2 Answers

After a lot of digging, the answer turned out to be somewhat obscure.

  • background-color does not work. I had to use background
  • I also had to use -unico-inner-stroke-width

I ended up at a GTK3 CSS file for the Ubuntu theme itself to see what was happening, located here:

/usr/share/themes/Ambiance/gtk-3.0/gtk-widgets.css

I got the -unico-inner-stroke-width property from the CSS file above. I cannot determine why background-color in my script is being ignored, but it is, at least on Ubuntu 12.04.

I was also forced to 're-set' the background and border colors of the elements I was changing as they would otherwise appear strange. This is the minimum CSS I had to use

                    GtkMenuItem 
                    {
                        border:@bg_color;
                        background:@bg_color;
                    }

                    GtkMenuItem:hover
                    {
                        background:@selected_bg_color;
                    }

                    GtkWidget
                    {
                        border: @bg_color;
                    }

                    #mymenu:hover
                    {
                        color:@fg_color;
                        background: @bg_color;
                        -unico-inner-stroke-width: 0;
                    }

In this example, I am setting the hover color of a single GtkMenuItem to be the same as the background color, but if you want to set the color to something else, you'd have to change the background property as per your needs.

Result, a working MenuItem without a hover color

enter image description here

Here is the full Python code:

from gi.repository import Gtk, Gdk
import sys


class TrayIcon:

    def __init__(self):
        self.statusicon = Gtk.StatusIcon()
        self.statusicon.set_from_stock(Gtk.STOCK_MEDIA_PLAY)
        self.statusicon.connect("popup-menu", self.OnShowPopupMenu)
        self.statusicon.set_tooltip_text("HELLO")
        window = Gtk.Window()

    def OnShowPopupMenu(self, icon, button, time):

        display = Gdk.Display.get_default()
        screen = display.get_default_screen()

        css_provider = Gtk.CssProvider()

        gtk3Css = """GtkMenuItem {
                        border:@bg_color;
                        background:@bg_color;
                    }

                    GtkMenuItem:hover
                    {
                        background:@selected_bg_color;
                    }

                    GtkWidget
                    {
                        border: @bg_color;
                    }

                    #mymenu:hover
                    {
                        color:@fg_color;
                        background: @bg_color;
                        -unico-inner-stroke-width: 0;
                    }"""
        css_provider.load_from_data(gtk3Css)
        context = Gtk.StyleContext()
        context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

        menu = Gtk.Menu()
        #menu.set_name('mymenu')
        first = self.GetMenuItem("First")
        first.set_name('mymenu')
        second = self.GetMenuItem("Second")
        menu.append(first)
        menu.append(second)
        menu.show_all()
        menu.popup(None, None, lambda w,x: self.statusicon.position_menu(menu, self.statusicon), self.statusicon, 3, time)

    def GetMenuItem(self, txt):
    menuItem = Gtk.MenuItem()
    menuItem.set_label(txt)

    menuItem.connect("button_press_event", self.exit)

    return menuItem

    def exit(self, a,b):
    sys.exit()


TrayIcon()
Gtk.main()

If you wanted to set another background color, you could do this in the CSS above

                    GtkMenuItem:hover
                    {
                        background:purple;
                        -unico-inner-stroke-width: 0;
                    }

(or do it in #mymenu:hover)

enter image description here

In conclusion, I think this may have been a problem limited to Ubuntu 12.04 or GTK 3.4.2 which I determined by running,

pkg-config --modversion gtk+-3.0

But I do not have the expertise to determine the origin of this problem.

like image 78
Mendhak Avatar answered Oct 12 '22 07:10

Mendhak


Well it's C not python, but this works for me. I named the menu "mymenu" that way you can style it without using GtkLabel which would affect any other labels in the application.

/* COMPILE WITH: gcc -Wall -o icon3 `pkg-config --cflags --libs gtk+-3.0` icon3.c */

#include <gtk/gtk.h>
#include <string.h>  /* for CSS */

static void cb_left_click(GtkStatusIcon *icon, gpointer data)
{
 static GtkWidget *window = NULL;

if (window == NULL) {
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Status Icon");

    g_signal_connect( window, "delete-event", G_CALLBACK(gtk_main_quit), NULL );
    gtk_widget_show(window);
}
}

static void cb_right_click(GtkStatusIcon *icon, int button, int time, gpointer data)
{
    GtkWidget *menu;

menu = gtk_menu_new ();
gtk_widget_set_name(GTK_WIDGET(menu),"mymenu");
GtkWidget *item1 = gtk_menu_item_new_with_label("First");

GtkWidget *item2 = gtk_menu_item_new_with_label("Second");

gtk_menu_shell_append(GTK_MENU_SHELL(menu), item1);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item2);

    gtk_widget_show_all(menu);
    gtk_menu_popup(GTK_MENU(menu),
                        NULL,
                        NULL,
                        gtk_status_icon_position_menu,
                        icon,
                        button,
                        time);
}

int main(int argc, char *argv[])
{
GtkStatusIcon *icon;
/*-- CSS ------------------*/
  GtkCssProvider *provider;
  GdkDisplay *display;
  GdkScreen *screen;
/*---------------------------*/

gtk_init(&argc, &argv);

icon = gtk_status_icon_new_from_stock (GTK_STOCK_MEDIA_PLAY);

g_signal_connect (G_OBJECT(icon), "activate", G_CALLBACK(cb_left_click), NULL);
g_signal_connect (G_OBJECT(icon), "popup-menu", G_CALLBACK(cb_right_click), NULL);

/*---------------- CSS ----------------------------------------------------------------------------------------------------*/
  provider = gtk_css_provider_new ();
  display = gdk_display_get_default ();
  screen = gdk_display_get_default_screen (display);
  gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),     GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

  gsize bytes_written, bytes_read;

 const gchar* home = "/home/mike/icon3.css";     

  GError *error = 0;

  gtk_css_provider_load_from_path (provider,
                               g_filename_to_utf8(home, strlen(home),
                               &bytes_read, &bytes_written, &error),
                               NULL);
  g_object_unref (provider);
/*-------------------------------------------------------------------------------------------------------------------------*/

    gtk_main();
    return 0;
}

Css file:

#mymenu {       
    background-color: white;
    color: green;
    font-weight:bold;
}

#mymenu :hover {
    background-color: red;
    color: blue;
    font-weight:bold;
}
like image 43
mike Avatar answered Oct 12 '22 09:10

mike