github.com/shurcool/trayhost@v0.0.0-20181020202213-114974ef9e16/platform/linux/tray.c (about) 1 #ifndef NATIVE_C 2 #define NATIVE_C 3 4 #include <stdio.h> 5 #include <dlfcn.h> 6 #include <unistd.h> 7 #include <gtk/gtk.h> 8 #include <gio/gio.h> 9 #include <gdk-pixbuf/gdk-pixbuf.h> 10 #include <string.h> 11 #include <libappindicator/app-indicator.h> 12 13 static const char *icon = NULL; 14 static size_t iconSize = 0; 15 static const char *menu_title = NULL; 16 static const char *url = NULL; 17 static GtkWidget *menu = NULL; 18 char tmpIconNameBuf[32]; 19 20 // implemented in go 21 extern void tray_callback(int itemId); 22 23 // internal wrapper for go callback 24 void _tray_callback(GtkMenuItem *item, gpointer user_data) 25 { 26 tray_callback(GPOINTER_TO_INT(user_data)); 27 } 28 29 // TODO: Implement. 30 void display_notification(int id, const char* title, const char* body, struct image imageData, double duration) 31 { 32 } 33 34 // TODO: Implement. 35 void clear_menu_items() {} 36 37 // TODO: Implement. 38 struct clipboard_content get_clipboard_content() 39 { 40 struct clipboard_content cc; 41 return cc; 42 } 43 44 // TODO: Implement. 45 void set_clipboard_string(const char* cp) 46 { 47 } 48 49 void add_menu_item(int id, const char* title, int disabled) { 50 GtkWidget *item = gtk_menu_item_new_with_label(title); 51 if (disabled == TRUE) { 52 gtk_widget_set_sensitive(item, FALSE); 53 } 54 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(_tray_callback), GINT_TO_POINTER(id)); 55 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 56 } 57 58 void add_separator_item() { 59 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); 60 } 61 62 typedef void* (*app_indicator_new_fun)(const gchar*, const gchar*, AppIndicatorCategory); 63 typedef void* (*app_indicator_set_status_fun)(AppIndicator*, AppIndicatorStatus); 64 typedef void* (*app_indicator_set_attention_icon_full_fun) (AppIndicator*, const gchar* ,const gchar*); 65 typedef void* (*app_indicator_set_menu_fun)(AppIndicator*,GtkMenu*); 66 67 void create_indicator(void *handle) 68 { 69 app_indicator_new_fun app_indicator_new; 70 app_indicator_set_status_fun app_indicator_set_status; 71 app_indicator_set_menu_fun app_indicator_set_menu; 72 73 app_indicator_new = dlsym(handle, "app_indicator_new"); 74 app_indicator_set_status = dlsym(handle, "app_indicator_set_status"); 75 app_indicator_set_menu = dlsym(handle, "app_indicator_set_menu"); 76 77 // write icon to temp file, otherwise imposible to set in libappindicator 78 int fd = -1; 79 memset(tmpIconNameBuf, 0, sizeof(tmpIconNameBuf)); 80 strncpy(tmpIconNameBuf,"/tmp/storageguiicon-XXXXXX",26); 81 fd = mkstemp(tmpIconNameBuf); 82 83 if (fd > 0) { 84 if(write(fd, icon, iconSize) == -1) { 85 fprintf(stderr, "Failed to write icon data into temp file\n"); 86 } 87 } else { 88 fprintf(stderr, "Failed to create temp file for icon\n"); 89 } 90 91 AppIndicator *indicator = app_indicator_new (menu_title, 92 tmpIconNameBuf, 93 APP_INDICATOR_CATEGORY_APPLICATION_STATUS); 94 95 app_indicator_set_status (indicator, APP_INDICATOR_STATUS_ACTIVE); 96 app_indicator_set_menu (indicator, GTK_MENU (menu)); 97 } 98 99 static void tray_icon_on_menu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data) 100 { 101 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); 102 } 103 104 void create_status_icon() 105 { 106 GError *error = NULL; 107 GInputStream *stream = g_memory_input_stream_new_from_data(icon, iconSize, NULL); 108 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(stream, NULL, &error); 109 if (error) 110 fprintf(stderr, "Unable to create PixBuf: %s\n", error->message); 111 112 113 GtkStatusIcon *tray_icon = gtk_status_icon_new_from_pixbuf(pixbuf); 114 g_signal_connect(G_OBJECT(tray_icon), "popup-menu", G_CALLBACK(tray_icon_on_menu), NULL); 115 gtk_status_icon_set_tooltip_text(tray_icon, menu_title); 116 gtk_status_icon_set_visible(tray_icon, TRUE); 117 } 118 119 void init(const char* title, struct image imageData) 120 { 121 int argc = 0; 122 char *argv[] = { "" }; 123 gtk_init(&argc, (char***)&argv); 124 125 menu_title = title; 126 icon = imageData.bytes; 127 iconSize = imageData.length; 128 menu = gtk_menu_new(); 129 void *handle; 130 131 // check if system has libappindicator1 package 132 handle = dlopen("libappindicator.so.1", RTLD_LAZY); 133 if(!handle) { 134 create_status_icon(); 135 } else { 136 create_indicator(handle); 137 } 138 } 139 140 void native_loop() 141 { 142 gtk_widget_show_all(menu); 143 gtk_main (); 144 } 145 146 void exit_loop() 147 { 148 gtk_main_quit(); 149 } 150 151 152 #endif // NATIVE_C