Merge pull request #181 from fbrinker/add-linux-checkboxes

Add checkbox support for Linux
This commit is contained in:
joesis
2020-11-18 01:20:05 -08:00
committed by GitHub
7 changed files with 72 additions and 17 deletions
+1 -1
View File
@@ -78,7 +78,7 @@ On Linux Mint, `libxapp-dev` is also required .
To build `webview_example`, you also need to install `libwebkit2gtk-4.0-dev` and remove `webview_example/rsrc.syso` which is required on Windows.
* Submenu and checked menu items are not yet implemented
* Submenu items are not yet implemented
### Windows
+2 -2
View File
@@ -37,7 +37,7 @@ func onReady() {
systray.SetTitle("Awesome App")
systray.SetTooltip("Pretty awesome棒棒嗒")
mChange := systray.AddMenuItem("Change Me", "Change Me")
mChecked := systray.AddMenuItem("Unchecked", "Check Me")
mChecked := systray.AddMenuItemCheckbox("Unchecked", "Check Me", true)
mEnabled := systray.AddMenuItem("Enabled", "Enabled")
// Sets the icon of a menu item. Only available on Mac.
mEnabled.SetTemplateIcon(icon.Data, icon.Data)
@@ -46,7 +46,7 @@ func onReady() {
subMenuTop := systray.AddMenuItem("SubMenu", "SubMenu Test (top)")
subMenuMiddle := subMenuTop.AddSubMenuItem("SubMenu - Level 2", "SubMenu Test (middle)")
subMenuBottom := subMenuMiddle.AddSubMenuItem("SubMenu - Level 3", "SubMenu Test (bottom)")
subMenuBottom := subMenuMiddle.AddSubMenuItemCheckbox("SubMenu - Level 3", "SubMenu Test (bottom)", false)
subMenuBottom2 := subMenuMiddle.AddSubMenuItem("Panic!", "SubMenu Test (bottom)")
mUrl := systray.AddMenuItem("Open UI", "my home")
+34 -8
View File
@@ -44,6 +44,8 @@ type MenuItem struct {
disabled bool
// checked menu item has a tick before the title
checked bool
// has the menu item a checkbox (Linux)
isCheckable bool
// parent item, for sub menus
parent *MenuItem
}
@@ -58,13 +60,14 @@ func (item *MenuItem) String() string {
// newMenuItem returns a populated MenuItem object
func newMenuItem(title string, tooltip string, parent *MenuItem) *MenuItem {
return &MenuItem{
ClickedCh: make(chan struct{}),
id: atomic.AddUint32(&currentID, 1),
title: title,
tooltip: tooltip,
disabled: false,
checked: false,
parent: parent,
ClickedCh: make(chan struct{}),
id: atomic.AddUint32(&currentID, 1),
title: title,
tooltip: tooltip,
disabled: false,
checked: false,
isCheckable: false,
parent: parent,
}
}
@@ -109,14 +112,25 @@ func Quit() {
}
// AddMenuItem adds a menu item with the designated title and tooltip.
//
// It can be safely invoked from different goroutines.
// Created menu items are checkable on Windows and OSX by default. For Linux you have to use AddMenuItemCheckbox
func AddMenuItem(title string, tooltip string) *MenuItem {
item := newMenuItem(title, tooltip, nil)
item.update()
return item
}
// AddMenuItemCheckbox adds a menu item with the designated title and tooltip and a checkbox for Linux.
// It can be safely invoked from different goroutines.
// On Windows and OSX this is the same as calling AddMenuItem
func AddMenuItemCheckbox(title string, tooltip string, checked bool) *MenuItem {
item := newMenuItem(title, tooltip, nil)
item.isCheckable = true
item.checked = checked
item.update()
return item
}
// AddSeparator adds a separator bar to the menu
func AddSeparator() {
addSeparator(atomic.AddUint32(&currentID, 1))
@@ -124,12 +138,24 @@ func AddSeparator() {
// AddSubMenuItem adds a nested sub-menu item with the designated title and tooltip.
// It can be safely invoked from different goroutines.
// Created menu items are checkable on Windows and OSX by default. For Linux you have to use AddSubMenuItemCheckbox
func (item *MenuItem) AddSubMenuItem(title string, tooltip string) *MenuItem {
child := newMenuItem(title, tooltip, item)
child.update()
return child
}
// AddSubMenuItemCheckbox adds a nested sub-menu item with the designated title and tooltip and a checkbox for Linux.
// It can be safely invoked from different goroutines.
// On Windows and OSX this is the same as calling AddSubMenuItem
func (item *MenuItem) AddSubMenuItemCheckbox(title string, tooltip string, checked bool) *MenuItem {
child := newMenuItem(title, tooltip, item)
child.isCheckable = true
child.checked = checked
child.update()
return child
}
// SetTitle set the text to display on a menu item
func (item *MenuItem) SetTitle(title string) {
item.title = title
+1 -1
View File
@@ -10,7 +10,7 @@ void setIcon(const char* iconBytes, int length, bool template);
void setMenuItemIcon(const char* iconBytes, int length, int menuId, bool template);
void setTitle(char* title);
void setTooltip(char* tooltip);
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked);
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked, short isCheckable);
void add_separator(int menuId);
void hide_menu_item(int menuId);
void show_menu_item(int menuId);
+1 -1
View File
@@ -266,7 +266,7 @@ void setTooltip(char* ctooltip) {
runInMainThread(@selector(setTooltip:), (id)tooltip);
}
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked) {
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked, short isCheckable) {
MenuItem* item = [[MenuItem alloc] initWithId: menuId withParentMenuId: parentMenuId withTitle: title withTooltip: tooltip withDisabled: disabled withChecked: checked];
free(title);
free(tooltip);
+28 -4
View File
@@ -13,6 +13,7 @@ static char temp_file_name[PATH_MAX] = "";
typedef struct {
GtkWidget *menu_item;
int menu_id;
long signalHandlerId;
} MenuItemNode;
typedef struct {
@@ -21,6 +22,7 @@ typedef struct {
char* tooltip;
short disabled;
short checked;
short isCheckable;
} MenuItemInfo;
void registerSystray(void) {
@@ -90,22 +92,43 @@ gboolean do_add_or_update_menu_item(gpointer data) {
GList* it;
for(it = global_menu_items; it != NULL; it = it->next) {
MenuItemNode* item = (MenuItemNode*)(it->data);
if(item->menu_id == mii->menu_id){
if(item->menu_id == mii->menu_id) {
gtk_menu_item_set_label(GTK_MENU_ITEM(item->menu_item), mii->title);
if (mii->isCheckable) {
// We need to block the "activate" event, to emulate the same behaviour as in the windows version
// A Check/Uncheck does change the checkbox, but does not trigger the checkbox menuItem channel
g_signal_handler_block(GTK_CHECK_MENU_ITEM(item->menu_item), item->signalHandlerId);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->menu_item), mii->checked == 1);
g_signal_handler_unblock(GTK_CHECK_MENU_ITEM(item->menu_item), item->signalHandlerId);
}
break;
}
}
// menu id doesn't exist, add new item
if(it == NULL) {
GtkWidget *menu_item = gtk_menu_item_new_with_label(mii->title);
GtkWidget *menu_item;
if (mii->isCheckable) {
menu_item = gtk_check_menu_item_new_with_label(mii->title);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), mii->checked == 1);
} else {
menu_item = gtk_menu_item_new_with_label(mii->title);
}
int *id = malloc(sizeof(int));
*id = mii->menu_id;
g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(_systray_menu_item_selected), id);
long signalHandlerId = g_signal_connect_swapped(
G_OBJECT(menu_item),
"activate",
G_CALLBACK(_systray_menu_item_selected),
id
);
gtk_menu_shell_append(GTK_MENU_SHELL(global_tray_menu), menu_item);
MenuItemNode* new_item = malloc(sizeof(MenuItemNode));
new_item->menu_id = mii->menu_id;
new_item->signalHandlerId = signalHandlerId;
new_item->menu_item = menu_item;
GList* new_node = malloc(sizeof(GList));
new_node->data = new_item;
@@ -187,7 +210,7 @@ void setTooltip(char* ctooltip) {
void setMenuItemIcon(const char* iconBytes, int length, int menuId, bool template) {
}
void add_or_update_menu_item(int menu_id, int parent_menu_id, char* title, char* tooltip, short disabled, short checked) {
void add_or_update_menu_item(int menu_id, int parent_menu_id, char* title, char* tooltip, short disabled, short checked, short isCheckable) {
// TODO: add support for sub-menus
MenuItemInfo *mii = malloc(sizeof(MenuItemInfo));
mii->menu_id = menu_id;
@@ -195,6 +218,7 @@ void add_or_update_menu_item(int menu_id, int parent_menu_id, char* title, char*
mii->tooltip = tooltip;
mii->disabled = disabled;
mii->checked = checked;
mii->isCheckable = isCheckable;
g_idle_add(do_add_or_update_menu_item, mii);
}
+5
View File
@@ -55,6 +55,10 @@ func addOrUpdateMenuItem(item *MenuItem) {
if item.checked {
checked = 1
}
var isCheckable C.short
if item.isCheckable {
isCheckable = 1
}
var parentID uint32 = 0
if item.parent != nil {
parentID = item.parent.id
@@ -66,6 +70,7 @@ func addOrUpdateMenuItem(item *MenuItem) {
C.CString(item.tooltip),
disabled,
checked,
isCheckable,
)
}