pax_global_header00006660000000000000000000000064132416621750014521gustar00rootroot0000000000000052 comment=0d61c343c083e7c1d6e07d469f530cdb51d0fe67 budgie-indicator-applet-0.5/000077500000000000000000000000001324166217500160615ustar00rootroot00000000000000budgie-indicator-applet-0.5/.clang-format000066400000000000000000000050461324166217500204410ustar00rootroot00000000000000--- AccessModifierOffset: 0 AlignAfterOpenBracket: true AlignConsecutiveAssignments: false #uncomment for clang 3.9 #AlignConsecutiveDeclarations: false AlignEscapedNewlinesLeft: false AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false # AlwaysBreakAfterDefinitionReturnType: None #uncomment for clang 3.9 #AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: false BinPackArguments: false BinPackParameters: true # BraceWrapping: (not set since BreakBeforeBraces is not Custom) BreakBeforeBinaryOperators: None # BreakAfterJavaFieldAnnotations: (not java) BreakBeforeBinaryOperators: None BreakBeforeBraces: Linux BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false #uncomment for clang 3.9 #BreakStringLiterals: false ColumnLimit: 100 CommentPragmas: '\*\<' ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: false DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false ForEachMacros: [ ] #Uncomment for clang 3.9 #IncludeCategories: # - Regex: '^"' # Priority: 1 # IncludeIsMainRegex: (project doesn't use a main includes that can add other includes via regex) IndentCaseLabels: false IndentWidth: 8 IndentWrappedFunctionNames: false # JavaScriptQuotes: (not javascript) KeepEmptyLinesAtTheStartOfBlocks: false Language: Cpp MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None # ObjCBlockIndentWidth: (not objc) # ObjCSpaceAfterProperty: (not objc) # ObjCSpaceBeforeProtocolList: (not objc) PenaltyBreakBeforeFirstCallParameter: 400 PenaltyBreakComment: 0 # PenaltyBreakFirstLessLess: (not cpp) PenaltyBreakString: 500 PenaltyExcessCharacter: 10000 PenaltyReturnTypeOnItsOwnLine: 600 PointerAlignment: Right #uncomment for clang 3.9 #ReflowComments: true #uncomment for clang 3.9 #SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInCStyleCastParentheses: false # SpacesInContainerLiterals: (not objc or javascript) SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 8 UseTab: Never ... budgie-indicator-applet-0.5/.gitignore000066400000000000000000000003731324166217500200540ustar00rootroot00000000000000# Object files *.o *.ko *.obj *.elf # Precompiled Headers *.gch *.pch # Libraries *.lib *.a *.la *.lo # Shared objects (inc. Windows DLLs) *.dll *.so *.so.* *.dylib # Executables *.exe *.out *.app *.i*86 *.x86_64 *.hex # Debug files *.dSYM/ *.su budgie-indicator-applet-0.5/Makefile.am000066400000000000000000000000211324166217500201060ustar00rootroot00000000000000SUBDIRS = \ src budgie-indicator-applet-0.5/README.md000066400000000000000000000034021324166217500173370ustar00rootroot00000000000000budgie-indicator-applet ----------------------- AppIndicator applet for budgie-desktop. *Help required to resolve the TODO and ENHANCEMENTS lists* To compile: sudo apt install git libtool dpkg-dev intltool libtool libgtk-3-dev libido3-0.1-dev libindicator3-dev libpeas-dev budgie-core-dev git clone https://github.com/budgie-remix/budgie-indicator-applet cd budgie-indicator-applet ./autogen.sh --prefix=/usr make sudo make install To run: install the recommended packages sudo apt install gir1.2-appindicator3-0.1 budgie-panel --replace & Use Raven to add the applet to the panel. TODO ----- - [x] Applet background needs to use panel colour for inbuilt-theme - [x] Code cleanup - copyright statements, unused code, change boilerplate budgie-applet - [x] Correct debian/copyright - [x] check all the build dependencies are actually needed Enhancements ----- - [ ] For the applet settings add capability to change indicator order - [x] Appindicator spacing is too wide when not using built-in-theme - [x] Applet background needs to respect raven stylise regions option - [x] Applet background needs to use panel colour for user-defined theme - [ ] When used with the system-tray applet hide the network applet icon rather than permanently hiding - [ ] Change from using GtkMenu and GtkMenuItem to GtkButtonBox/GtkButton and therefore allow GtkPopover when button click *Tips for Development* Use the following to run GTK Inspector - use to investigate CSS and other properties GTK_DEBUG=interactive budgie-panel --replace Use the following to print out g_debug messages i.e. use "zzz" in the g_debug to show in the grep filter G_MESSAGES_DEBUG=all budgie-panel --replace | grep "zzz" budgie-indicator-applet-0.5/autogen.sh000077500000000000000000000003371324166217500200650ustar00rootroot00000000000000#!/bin/sh set -e autoreconf --force --install --symlink --warnings=all args="\ --sysconfdir=/etc \ --localstatedir=/var \ --prefix=/usr \ --enable-silent-rules" ./configure CFLAGS="-g -O1 $CFLAGS" $args "$@" make clean budgie-indicator-applet-0.5/common.mk000066400000000000000000000005151324166217500177030ustar00rootroot00000000000000AM_CFLAGS = \ -fstack-protector -Wall -pedantic \ -Wstrict-prototypes -Wundef -fno-common \ -Werror-implicit-function-declaration \ -Wformat -Wformat-security -Werror=format-security \ -Wno-conversion -Wunused-variable -Wunreachable-code \ -Wall -W -D_FORTIFY_SOURCE=2 -std=c11 -fPIC budgie-indicator-applet-0.5/configure.ac000066400000000000000000000035341324166217500203540ustar00rootroot00000000000000AC_INIT([budgie-indicator-applet], 0.2, [fossfreedom@ubuntu.com], [budgie-indicator-applet], [https://github.com/budgie-remix/budgie-indicator-applet]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([-Wno-portability no-dist-gzip dist-xz foreign subdir-objects]) AC_PROG_CC AC_PROG_CC_STDC LT_PREREQ(2.2) AC_CONFIG_HEADERS([config.h]) AC_PREFIX_DEFAULT(/usr/local) AM_SILENT_RULES([yes]) LT_INIT([disable-static]) AC_CONFIG_MACRO_DIR([m4]) m4_define([budgie_required_version], [1]) # Note budgie-1.0 depends on peas, gtk, etc. Sorta your package managers # business to make sure those deps are satisfied. # Also note this is just for the C and Vala subprojects! PKG_CHECK_MODULES(BUDGIE_PLUGIN, budgie-1.0 >= budgie_required_version ) INDICATOR_API_VERSION=3 INDICATOR_REQUIRED_VERSION=0.3.90 INDICATOR_NG_VERSION=0.5 INDICATOR_PKG=indicator$INDICATOR_API_VERSION-0.4 PKG_CHECK_MODULES(INDICATOR, $INDICATOR_PKG >= $INDICATOR_NG_VERSION libido3-0.1 >= 0.3.4, [AC_DEFINE(HAVE_INDICATOR_NG, 1, "New style indicators support")]) AC_SUBST(INDICATOR_CFLAGS) AC_SUBST(INDICATOR_LIBS) INDICATORDIR=`$PKG_CONFIG --variable=indicatordir $INDICATOR_PKG` INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir $INDICATOR_PKG` AC_SUBST(INDICATORDIR) AC_SUBST(INDICATORICONSDIR) AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT AC_MSG_RESULT([ budgie-indicator-applet $VERSION ======== prefix: ${prefix} libdir: ${libdir} sysconfdir: ${sysconfdir} exec_prefix: ${exec_prefix} bindir: ${bindir} datarootdir: ${datarootdir} compiler: ${CC} cflags: ${CFLAGS} ldflags: ${LDFLAGS} ]) budgie-indicator-applet-0.5/src/000077500000000000000000000000001324166217500166505ustar00rootroot00000000000000budgie-indicator-applet-0.5/src/AppIndicatorApplet.plugin000066400000000000000000000003371324166217500236160ustar00rootroot00000000000000[Plugin] Module=appindicatorapplet.so Name=AppIndicator Applet Description=AppIndicator Applet Authors=David Mohammed Copyright=Copyright © 2016-2017 David Mohammed Website=https://ubuntubudgie.org Icon=user-home-symbolic budgie-indicator-applet-0.5/src/Makefile.am000066400000000000000000000016351324166217500207110ustar00rootroot00000000000000include $(top_srcdir)/common.mk plugindir = $(libdir)/budgie-desktop/plugins appindicatorappletdir = $(plugindir)/appindicator-applet appindicatorapplet_LTLIBRARIES = \ libappindicatorapplet.la libappindicatorapplet_la_SOURCES = \ applet-main.c \ applet.c \ applet.h \ plugin.c \ plugin.h libappindicatorapplet_la_CFLAGS = \ $(BUDGIE_PLUGIN_CFLAGS) \ $(AM_CFLAGS) \ -DG_LOG_DOMAIN=\""Indicator-Applet"\" \ -DDATADIR=\""$(datadir)"\" \ -DINDICATOR_DIR=\""$(INDICATORDIR)"\" \ -DINDICATOR_ICONS_DIR=\""$(INDICATORICONSDIR)"\" \ -DINDICATOR_APPLET \ -I$(srcdir)/.. \ $(APPLET_CFLAGS) \ $(INDICATOR_CFLAGS) libappindicatorapplet_la_LIBADD = \ $(BUDGIE_PLUGIN_LIBS) \ $(APPLET_LIBS) \ $(INDICATOR_LIBS) \ -lX11 libappindicatorapplet_la_LDFLAGS = \ -module \ -avoid-version \ -shared \ $(AM_LDFLAGS) appindicatorapplet_DATA = \ AppIndicatorApplet.plugin EXTRA_DIST = \ AppIndicatorApplet.plugin budgie-indicator-applet-0.5/src/applet-main.c000066400000000000000000000623631324166217500212350ustar00rootroot00000000000000/* A small wrapper utility to load indicators and put them as menu items into the mate-panel using it's applet interface. Copyright 2009-2010 Canonical Ltd., 2016-2017 David Mohammed Authors: Ted Gould David Mohammed This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include //#include #include #include static gchar *indicator_order[] = { "libapplication.so", "libmessaging.so", "libsoundmenu.so", "libdatetime.so", "libsession.so", NULL }; static gchar *blacklist_applets[] = { "nm-applet", 0 }; BudgiePanelPosition orient = BUDGIE_PANEL_POSITION_NONE; GtkPackDirection packdirection = GTK_ORIENTATION_HORIZONTAL; #define MENU_DATA_INDICATOR_OBJECT "indicator-object" #define MENU_DATA_INDICATOR_ENTRY "indicator-entry" #define IO_DATA_ORDER_NUMBER "indicator-order-number" static void update_accessible_desc(IndicatorObjectEntry *entry, GtkWidget *menuitem); /************* * main * ***********/ /************* * log files * ***********/ #define LOG_FILE_NAME "indicator-applet.log" GOutputStream *log_file = NULL; /******************** * Environment Names * *******************/ #define INDICATOR_SPECIFIC_ENV "indicator-applet-original" static const gchar *indicator_env[] = { "indicator-applet", INDICATOR_SPECIFIC_ENV, NULL }; /************* * init function * ***********/ static gint name2order(const gchar *name) { int i; for (i = 0; indicator_order[i] != NULL; i++) { if (g_strcmp0(name, indicator_order[i]) == 0) { return i; } } return -1; } typedef struct _incoming_position_t incoming_position_t; struct _incoming_position_t { gint objposition; gint entryposition; gint menupos; gboolean found; }; /* This function helps by determining where in the menu list this new entry should be placed. It compares the objects that they're on, and then the individual entries. Each is progressively more expensive. */ static void place_in_menu(GtkWidget *widget, gpointer user_data) { incoming_position_t *position = (incoming_position_t *)user_data; if (position->found) { /* We've already been placed, just finish the foreach */ return; } IndicatorObject *io = INDICATOR_OBJECT(g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_OBJECT)); g_assert(io != NULL); gint objposition = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER)); /* We've already passed it, well, then this is where we should be be. Stop! */ if (objposition > position->objposition) { position->found = TRUE; return; } /* The objects don't match yet, keep looking */ if (objposition < position->objposition) { position->menupos++; return; } /* The objects are the same, let's start looking at entries. */ IndicatorObjectEntry *entry = (IndicatorObjectEntry *)g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY); gint entryposition = indicator_object_get_location(io, entry); if (entryposition > position->entryposition) { position->found = TRUE; return; } if (entryposition < position->entryposition) { position->menupos++; return; } /* We've got the same object and the same entry. Well, let's just put it right here then. */ position->found = TRUE; return; } static void something_shown(__attribute__((unused)) GtkWidget *widget, gpointer user_data) { g_debug("zzz something shown"); GtkWidget *menuitem = GTK_WIDGET(user_data); gtk_widget_show(menuitem); } static void something_hidden(__attribute__((unused)) GtkWidget *widget, gpointer user_data) { g_debug("zzz something hidden"); GtkWidget *menuitem = GTK_WIDGET(user_data); gtk_widget_hide(menuitem); } static void sensitive_cb(GObject *obj, __attribute__((unused)) GParamSpec *pspec, gpointer user_data) { g_debug("zzz something made sensitive"); g_return_if_fail(GTK_IS_WIDGET(obj)); g_return_if_fail(GTK_IS_WIDGET(user_data)); gtk_widget_set_sensitive(GTK_WIDGET(user_data), gtk_widget_get_sensitive(GTK_WIDGET(obj))); return; } static void entry_activated(GtkWidget *widget, gpointer user_data) { g_return_if_fail(GTK_IS_WIDGET(widget)); gpointer pio = g_object_get_data(G_OBJECT(widget), "indicator"); g_return_if_fail(INDICATOR_IS_OBJECT(pio)); IndicatorObject *io = INDICATOR_OBJECT(pio); return indicator_object_entry_activate(io, (IndicatorObjectEntry *)user_data, gtk_get_current_event_time()); } static gboolean entry_scrolled(GtkWidget *menuitem, GdkEventScroll *event, __attribute__((unused)) gpointer data) { IndicatorObject *io = g_object_get_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_OBJECT); IndicatorObjectEntry *entry = g_object_get_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_ENTRY); g_return_val_if_fail(INDICATOR_IS_OBJECT(io), FALSE); g_signal_emit_by_name(io, "scroll", 1, event->direction); g_signal_emit_by_name(io, "scroll-entry", entry, 1, event->direction); g_signal_emit_by_name(io, INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED, entry, 1, event->direction); return FALSE; } static void accessible_desc_update_cb(GtkWidget *widget, gpointer userdata) { gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY); if (data != userdata) { return; } IndicatorObjectEntry *entry = (IndicatorObjectEntry *)data; update_accessible_desc(entry, widget); } static void accessible_desc_update(__attribute__((unused)) IndicatorObject *io, IndicatorObjectEntry *entry, GtkWidget *menubar) { gtk_container_foreach(GTK_CONTAINER(menubar), accessible_desc_update_cb, entry); return; } GtkCssProvider *css_provider = NULL; static void entry_added(IndicatorObject *io, IndicatorObjectEntry *entry, GtkWidget *menubar) { g_debug("zzz Signal: Entry Added"); gboolean something_visible = FALSE; gboolean something_sensitive = FALSE; GtkStyleContext *context; GtkCssProvider *css_provider = NULL; /* * we don't want to have the nm-applet being displayed * budgie-desktop provides this */ if (entry->name_hint != NULL) { int loop = 0; while (blacklist_applets[loop]) { if (strstr(entry->name_hint, blacklist_applets[loop]) != NULL) { return; } loop++; } g_debug("zzz %s", entry->name_hint); } else { g_debug("zzz no name_hint"); } GtkWidget *menuitem = gtk_menu_item_new(); GtkWidget *box = (orient == BUDGIE_PANEL_POSITION_TOP || orient == BUDGIE_PANEL_POSITION_BOTTOM) ? gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3) : gtk_box_new(GTK_ORIENTATION_VERTICAL, 3); /* Allows indicators to receive mouse scroll event in GTK+3 */ gtk_widget_add_events(GTK_WIDGET(menuitem), GDK_SCROLL_MASK); g_object_set_data(G_OBJECT(menuitem), "indicator", io); g_object_set_data(G_OBJECT(menuitem), "box", box); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(entry_activated), entry); g_signal_connect(G_OBJECT(menuitem), "scroll-event", G_CALLBACK(entry_scrolled), entry); if (entry->image != NULL) { g_debug("zzz have an image"); gtk_image_set_pixel_size(entry->image, 22); gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(entry->image), FALSE, FALSE, 1); if (gtk_widget_get_visible(GTK_WIDGET(entry->image))) { g_debug("zzz and is visible"); something_visible = TRUE; } if (gtk_widget_get_sensitive(GTK_WIDGET(entry->image))) { something_sensitive = TRUE; } g_signal_connect(G_OBJECT(entry->image), "show", G_CALLBACK(something_shown), menuitem); g_signal_connect(G_OBJECT(entry->image), "hide", G_CALLBACK(something_hidden), menuitem); g_signal_connect(G_OBJECT(entry->image), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem); } if (entry->label != NULL) { g_debug("zzz have a label"); switch (orient) { case BUDGIE_PANEL_POSITION_LEFT: gtk_label_set_angle(GTK_LABEL(entry->label), 270.0); break; case BUDGIE_PANEL_POSITION_RIGHT: gtk_label_set_angle(GTK_LABEL(entry->label), 90.0); break; default: // g_assert(1==2); gtk_label_set_angle(GTK_LABEL(entry->label), 0.0); } gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(entry->label), FALSE, FALSE, 1); if (gtk_widget_get_visible(GTK_WIDGET(entry->label))) { g_debug("zzz and is visible"); something_visible = TRUE; } if (gtk_widget_get_sensitive(GTK_WIDGET(entry->label))) { something_sensitive = TRUE; } g_signal_connect(G_OBJECT(entry->label), "show", G_CALLBACK(something_shown), menuitem); g_signal_connect(G_OBJECT(entry->label), "hide", G_CALLBACK(something_hidden), menuitem); g_signal_connect(G_OBJECT(entry->label), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem); } /* for the appindicator (menuitem) we need to style it with budgie-menubar * otherwise * all submenus are transparent for the system theme */ context = gtk_widget_get_style_context(GTK_WIDGET(menuitem)); gtk_style_context_add_class(context, "budgie-menubar"); context = gtk_widget_get_style_context(GTK_WIDGET(menubar)); gtk_style_context_remove_class(context, "menubar"); css_provider = gtk_css_provider_new(); gtk_css_provider_load_from_data(css_provider, ".budgie-menubar { \n" " padding-left: 2px; \n" " padding-right: 2px; \n" "} \n", -1, NULL); gtk_style_context_add_provider(GTK_STYLE_CONTEXT( gtk_widget_get_style_context(GTK_WIDGET(menuitem))), GTK_STYLE_PROVIDER(css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_debug("zzz adding budgie-menubar"); gtk_container_add(GTK_CONTAINER(menuitem), box); gtk_widget_show(box); if (entry->menu != NULL) { gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), GTK_WIDGET(entry->menu)); } incoming_position_t position; position.objposition = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER)); position.entryposition = indicator_object_get_location(io, entry); position.menupos = 0; position.found = FALSE; gtk_container_foreach(GTK_CONTAINER(menubar), place_in_menu, &position); gtk_menu_shell_insert(GTK_MENU_SHELL(menubar), menuitem, position.menupos); g_debug("zzz just about there"); if (something_visible) { if (entry->accessible_desc != NULL) { update_accessible_desc(entry, menuitem); } g_debug("zzz final show"); gtk_widget_show(menuitem); } gtk_widget_set_sensitive(menuitem, something_sensitive); g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_ENTRY, entry); g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_OBJECT, io); return; } static void entry_removed_cb(GtkWidget *widget, gpointer userdata) { gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY); if (data != userdata) { return; } IndicatorObjectEntry *entry = (IndicatorObjectEntry *)data; if (entry->label != NULL) { g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_shown), widget); g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_hidden), widget); g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(sensitive_cb), widget); } if (entry->image != NULL) { g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_shown), widget); g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_hidden), widget); g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(sensitive_cb), widget); } gtk_widget_destroy(widget); return; } static void entry_removed(IndicatorObject *io G_GNUC_UNUSED, IndicatorObjectEntry *entry, gpointer user_data) { g_debug("Signal: Entry Removed"); gtk_container_foreach(GTK_CONTAINER(user_data), entry_removed_cb, entry); return; } static void entry_moved_find_cb(GtkWidget *widget, gpointer userdata) { gpointer *array = (gpointer *)userdata; if (array[1] != NULL) { return; } gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY); if (data != array[0]) { return; } array[1] = widget; return; } /* Gets called when an entry for an object was moved. */ static void entry_moved(IndicatorObject *io, IndicatorObjectEntry *entry, gint old G_GNUC_UNUSED, gint new G_GNUC_UNUSED, gpointer user_data) { GtkWidget *menubar = GTK_WIDGET(user_data); gpointer array[2]; array[0] = entry; array[1] = NULL; gtk_container_foreach(GTK_CONTAINER(menubar), entry_moved_find_cb, array); if (array[1] == NULL) { g_warning("Moving an entry that isn't in our menus."); return; } GtkWidget *mi = GTK_WIDGET(array[1]); g_object_ref(G_OBJECT(mi)); gtk_container_remove(GTK_CONTAINER(menubar), mi); incoming_position_t position; position.objposition = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER)); position.entryposition = indicator_object_get_location(io, entry); position.menupos = 0; position.found = FALSE; gtk_container_foreach(GTK_CONTAINER(menubar), place_in_menu, &position); gtk_menu_shell_insert(GTK_MENU_SHELL(menubar), mi, position.menupos); g_object_unref(G_OBJECT(mi)); return; } static void menu_show(IndicatorObject *io, IndicatorObjectEntry *entry, __attribute__((unused)) guint32 timestamp, gpointer user_data) { GtkWidget *menubar = GTK_WIDGET(user_data); if (entry == NULL) { /* Close any open menus instead of opening one */ GList *entries = indicator_object_get_entries(io); GList *entry = NULL; for (entry = entries; entry != NULL; entry = g_list_next(entry)) { IndicatorObjectEntry *entrydata = (IndicatorObjectEntry *)entry->data; gtk_menu_popdown(entrydata->menu); } g_list_free(entries); /* And tell the menubar to exit activation mode too */ gtk_menu_shell_cancel(GTK_MENU_SHELL(menubar)); return; } } static void update_accessible_desc(IndicatorObjectEntry *entry, GtkWidget *menuitem) { /* We need to deal with the use case where the contents of the label overrides what is found in the atk object's name, or at least orca speaks the label instead of the atk object name. */ AtkObject *menuitem_obj = gtk_widget_get_accessible(menuitem); if (menuitem_obj == NULL) { /* Should there be an error printed here? */ return; } if (entry->accessible_desc != NULL) { atk_object_set_name(menuitem_obj, entry->accessible_desc); } else { atk_object_set_name(menuitem_obj, ""); } return; } static void load_indicator(GtkWidget *menubar, IndicatorObject *io, const gchar *name) { /* Set the environment it's in */ indicator_object_set_environment(io, (const GStrv)indicator_env); g_debug("zzz load_indicator %s", name); /* Attach the 'name' to the object */ int pos = name2order(name); g_object_set_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER, GINT_TO_POINTER(pos)); /* Connect to its signals */ g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, G_CALLBACK(entry_added), menubar); g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, G_CALLBACK(entry_removed), menubar); g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED, G_CALLBACK(entry_moved), menubar); g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW, G_CALLBACK(menu_show), menubar); g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE, G_CALLBACK(accessible_desc_update), menubar); /* Work on the entries */ GList *entries = indicator_object_get_entries(io); GList *entry = NULL; for (entry = entries; entry != NULL; entry = g_list_next(entry)) { IndicatorObjectEntry *entrydata = (IndicatorObjectEntry *)entry->data; entry_added(io, entrydata, menubar); } g_list_free(entries); } /* #define INDICATOR_SERVICE_DIR "/usr/share/unity/indicators" void load_indicators_from_indicator_files (GtkWidget *menubar, gint *indicators_loaded) { GDir *dir; const gchar *name; GError *error = NULL; dir = g_dir_open (INDICATOR_SERVICE_DIR, 0, &error); if (!dir) { g_warning ("unable to open indicator service file directory: %s", error->message); g_error_free (error); return; } gint count = 0; while ((name = g_dir_read_name (dir))) { gchar *filename; IndicatorNg *indicator; filename = g_build_filename (INDICATOR_SERVICE_DIR, name, NULL); indicator = indicator_ng_new_for_profile (filename, "desktop", &error); g_free (filename); *#ifdef INDICATOR_APPLET_APPMENU if (g_strcmp0(name, "com.canonical.indicator.appmenu")) { continue; } #else if (!g_strcmp0(name, "com.canonical.indicator.appmenu")) { continue; } #endif #ifdef INDICATOR_APPLET if (!g_strcmp0(name, "com.canonical.indicator.me")) { continue; } if (!g_strcmp0(name, "com.canonical.indicator.datetime")) { continue; } #endif * if (indicator) { load_indicator(menubar, INDICATOR_OBJECT (indicator), name); count++; }else{ g_warning ("unable to load '%s': %s", name, error->message); g_clear_error (&error); } } *indicators_loaded += count; g_dir_close (dir); } */ static gboolean load_module(const gchar *name, GtkWidget *menubar) { g_debug("Looking at Module: %s", name); g_return_val_if_fail(name != NULL, FALSE); if (!g_str_has_suffix(name, G_MODULE_SUFFIX)) { return FALSE; } g_debug("Loading Module: %s", name); /* Build the object for the module */ gchar *fullpath = g_build_filename(INDICATOR_DIR, name, NULL); IndicatorObject *io = indicator_object_new_from_file(fullpath); g_free(fullpath); load_indicator(menubar, io, name); return TRUE; } void load_modules(GtkWidget *menubar, gint *indicators_loaded) { if (g_file_test(INDICATOR_DIR, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) { GDir *dir = g_dir_open(INDICATOR_DIR, 0, NULL); const gchar *name; gint count = 0; while ((name = g_dir_read_name(dir)) != NULL) { if (!g_strcmp0(name, "libappmenu.so")) { continue; } if (!g_strcmp0(name, "libme.so")) { continue; } if (!g_strcmp0(name, "libdatetime.so")) { continue; } g_debug("zzz a: %s", name); if (load_module(name, menubar)) { count++; } } *indicators_loaded += count; g_dir_close(dir); } } void hotkey_filter(char *keystring G_GNUC_UNUSED, gpointer data) { g_return_if_fail(GTK_IS_MENU_SHELL(data)); /* Oh, wow, it's us! */ GList *children = gtk_container_get_children(GTK_CONTAINER(data)); if (children == NULL) { g_debug("Menubar has no children"); return; } gtk_menu_shell_select_item(GTK_MENU_SHELL(data), GTK_WIDGET(g_list_last(children)->data)); g_list_free(children); return; } gboolean menubar_on_draw(GtkWidget *widget, cairo_t *cr, GtkWidget *menubar) { if (gtk_widget_has_focus(menubar)) gtk_paint_focus(gtk_widget_get_style(widget), cr, gtk_widget_get_state(menubar), widget, "menubar-applet", 0, 0, -1, -1); return FALSE; } #ifdef N_ #undef N_ #endif #define N_(x) x budgie-indicator-applet-0.5/src/applet.c000066400000000000000000000204161324166217500203040ustar00rootroot00000000000000/** * Copyright (C) 2016-2017 David Mohammed * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #define _GNU_SOURCE #include "applet.h" #include #include #include void load_modules(GtkWidget *menubar, gint *indicators_loaded); void load_indicators_from_indicator_files(GtkWidget *menubar, gint *indicators_loaded); #define MENU_DATA_INDICATOR_OBJECT "indicator-object" #define MENU_DATA_INDICATOR_ENTRY "indicator-entry" #define IO_DATA_ORDER_NUMBER "indicator-order-number" extern GtkPackDirection packdirection; extern BudgiePanelPosition orient; static gboolean swap_orient_cb(GtkWidget *item, gpointer data) { GtkWidget *from = (GtkWidget *)data; GtkWidget *to = (GtkWidget *)g_object_get_data(G_OBJECT(from), "to"); g_object_ref(G_OBJECT(item)); gtk_container_remove(GTK_CONTAINER(from), item); if (GTK_IS_LABEL(item)) { switch (packdirection) { case GTK_PACK_DIRECTION_LTR: gtk_label_set_angle(GTK_LABEL(item), 0.0); break; case GTK_PACK_DIRECTION_TTB: gtk_label_set_angle(GTK_LABEL(item), (orient == BUDGIE_PANEL_POSITION_LEFT) ? 270.0 : 90.0); break; default: break; } } gtk_box_pack_start(GTK_BOX(to), item, FALSE, FALSE, 0); return TRUE; } static gboolean reorient_box_cb(GtkWidget *menuitem, gpointer data) { GtkWidget *from = g_object_get_data(G_OBJECT(menuitem), "box"); GtkWidget *to = (packdirection == GTK_PACK_DIRECTION_LTR) ? gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0) : gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); g_object_set_data(G_OBJECT(from), "to", to); gtk_container_foreach(GTK_CONTAINER(from), (GtkCallback)swap_orient_cb, from); gtk_container_remove(GTK_CONTAINER(menuitem), from); gtk_container_add(GTK_CONTAINER(menuitem), to); g_object_set_data(G_OBJECT(menuitem), "box", to); gtk_widget_show_all(menuitem); return TRUE; } static void native_applet_real_panel_position_changed(BudgieApplet *base, BudgiePanelPosition position) { AppIndicatorApplet *self; self = (AppIndicatorApplet *)base; GtkWidget *menubar = self->menubar; switch (position) { case BUDGIE_PANEL_POSITION_NONE: g_debug("zzz changed none"); break; case BUDGIE_PANEL_POSITION_LEFT: case BUDGIE_PANEL_POSITION_RIGHT: orient = position; packdirection = GTK_PACK_DIRECTION_TTB; g_debug("zzz changed left/right"); break; default: g_debug("zzz changed horizontal"); orient = position; packdirection = GTK_PACK_DIRECTION_LTR; } if (orient != BUDGIE_PANEL_POSITION_NONE) { gtk_menu_bar_set_pack_direction(GTK_MENU_BAR(menubar), packdirection); gtk_container_foreach(GTK_CONTAINER(menubar), (GtkCallback)reorient_box_cb, NULL); } } G_DEFINE_DYNAMIC_TYPE_EXTENDED(AppIndicatorApplet, appindicator_applet, BUDGIE_TYPE_APPLET, 0, ) extern GtkCssProvider *css_provider; /** * Handle cleanup */ static void appindicator_applet_dispose(GObject *object) { G_OBJECT_CLASS(appindicator_applet_parent_class)->dispose(object); if (css_provider != NULL) { g_object_unref(css_provider); css_provider = NULL; } } /** * Class initialisation */ static void appindicator_applet_class_init(AppIndicatorAppletClass *klazz) { GObjectClass *obj_class = G_OBJECT_CLASS(klazz); /* gobject vtable hookup */ obj_class->dispose = appindicator_applet_dispose; ((BudgieAppletClass *)klazz)->panel_position_changed = (void (*)(BudgieApplet *, BudgiePanelPosition))native_applet_real_panel_position_changed; } /** * We have no cleaning ourselves to do */ static void appindicator_applet_class_finalize(__budgie_unused__ AppIndicatorAppletClass *klazz) { } static GtkWidget *eventbox = NULL; static GtkWidget *menubar = NULL; static gboolean delay_load_indicators(gpointer data) { gint indicators_loaded = 0; gtk_menu_bar_set_pack_direction(GTK_MENU_BAR(menubar), packdirection); load_modules(menubar, &indicators_loaded); if (indicators_loaded == 0) { /* A label to allow for click through */ GtkWidget *item = gtk_label_new("No Indicators"); gtk_container_add(GTK_CONTAINER(eventbox), item); gtk_widget_show(item); } else { gtk_container_add(GTK_CONTAINER(eventbox), menubar); gtk_widget_show(menubar); } return FALSE; } /** * Initialisation of basic UI layout and such */ static void appindicator_applet_init(AppIndicatorApplet *self) { GtkCssProvider *css_provider = NULL; menubar = gtk_menu_bar_new(); self->menubar = menubar; css_provider = gtk_css_provider_new(); #if GTK_CHECK_VERSION(3, 20, 0) gtk_css_provider_load_from_data(css_provider, "menubar { \n" " background: transparent; } \n" ".budgie-menubar { \n" " padding-left: 2px; \n" " padding-right: 2px; \n" "} \n", -1, NULL); #else gtk_css_provider_load_from_data(css_provider, ".menuitem { \n" " background: transparent; } \n" ".budgie-menubar { \n" " padding-left: 2px; \n" " padding-right: 2px; \n" "} \n", -1, NULL); #endif gtk_style_context_add_provider(GTK_STYLE_CONTEXT( gtk_widget_get_style_context(GTK_WIDGET(menubar))), GTK_STYLE_PROVIDER(css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); eventbox = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(self), eventbox); gtk_widget_show(eventbox); gtk_container_set_border_width(GTK_CONTAINER(menubar), 1); gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INDICATOR_ICONS_DIR); /* * leave this here - this is the entry point for indicators such as * indicator-messages. Currently these indicators don't display their * menu contents correctly - e.g. missing thunderbird from indicator-messages * drop-down. * load_indicators_from_indicator_files (menubar, &indicators_loaded); */ /* Show all of our things. */ gtk_widget_show_all(GTK_WIDGET(self)); g_timeout_add_seconds(1, delay_load_indicators, NULL); } void appindicator_applet_init_gtype(GTypeModule *module) { appindicator_applet_register_type(module); } BudgieApplet *appindicator_applet_new() { // return applet_construct(APPINDICATOR_TYPE_NATIVE_APPLET, uuid); return g_object_new(APPINDICATOR_TYPE_NATIVE_APPLET, NULL); } budgie-indicator-applet-0.5/src/applet.h000066400000000000000000000045411324166217500203120ustar00rootroot00000000000000/** * Copyright (C) 2016-2017 David Mohammed * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #pragma once #include #include #define __budgie_unused__ __attribute__((unused)) G_BEGIN_DECLS typedef struct _AppIndicatorApplet AppIndicatorApplet; typedef struct _AppIndicatorAppletClass AppIndicatorAppletClass; #define APPINDICATOR_TYPE_NATIVE_APPLET appindicator_applet_get_type() #define APPINDICATOR_NATIVE_APPLET(o) \ (G_TYPE_CHECK_INSTANCE_CAST((o), APPINDICATOR_TYPE_NATIVE_APPLET, AppIndicatorApplet)) #define APPINDICATOR_IS_NATIVE_APPLET(o) \ (G_TYPE_CHECK_INSTANCE_TYPE((o), APPINDICATOR_TYPE_NATIVE_APPLET)) #define APPINDICATOR_NATIVE_APPLET_CLASS(o) \ (G_TYPE_CHECK_CLASS_CAST((o), APPINDICATOR_TYPE_NATIVE_APPLET, AppIndicatorAppletClass)) #define APPINDICATOR_IS_NATIVE_APPLET_CLASS(o) \ (G_TYPE_CHECK_CLASS_TYPE((o), APPINDICATOR_TYPE_NATIVE_APPLET)) #define APPINDICATOR_NATIVE_APPLET_GET_CLASS(o) \ (G_TYPE_INSTANCE_GET_CLASS((o), APPINDICATOR_TYPE_NATIVE_APPLET, AppIndicatorAppletClass)) struct _AppIndicatorAppletClass { BudgieAppletClass parent_class; }; struct _AppIndicatorApplet { BudgieApplet parent; GSettings *settings; GtkWidget *menubar; }; GType appindicator_applet_get_type(void); /** * Public for the plugin to allow registration of types */ void appindicator_applet_init_gtype(GTypeModule *module); /** * Construct a new AppIndicatorApplet */ BudgieApplet *appindicator_applet_new(void); G_END_DECLS budgie-indicator-applet-0.5/src/plugin.c000066400000000000000000000056441324166217500203230ustar00rootroot00000000000000/** * Copyright (C) 2016-2017 David Mohammed * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #define _GNU_SOURCE #include #include "applet.h" #include "plugin.h" static void appindicator_native_plugin_iface_init(BudgiePluginIface *iface); G_DEFINE_DYNAMIC_TYPE_EXTENDED(AppIndicatorNativePlugin, appindicator_native_plugin, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE_DYNAMIC(BUDGIE_TYPE_PLUGIN, appindicator_native_plugin_iface_init)) /** * Return a new panel widget */ static BudgieApplet *native_applet_get_panel_widget(__budgie_unused__ BudgiePlugin *self, __budgie_unused__ gchar *uuid) { return appindicator_applet_new(); } /** * Handle cleanup */ static void appindicator_native_plugin_dispose(GObject *object) { G_OBJECT_CLASS(appindicator_native_plugin_parent_class)->dispose(object); } /** * Class initialisation */ static void appindicator_native_plugin_class_init(AppIndicatorNativePluginClass *klazz) { GObjectClass *obj_class = G_OBJECT_CLASS(klazz); /* gobject vtable hookup */ obj_class->dispose = appindicator_native_plugin_dispose; } /** * Implement the BudgiePlugin interface, i.e the factory method get_panel_widget */ static void appindicator_native_plugin_iface_init(BudgiePluginIface *iface) { iface->get_panel_widget = native_applet_get_panel_widget; } /** * No-op, just skips compiler errors */ static void appindicator_native_plugin_init(__budgie_unused__ AppIndicatorNativePlugin *self) { } /** * We have no cleaning ourselves to do */ static void appindicator_native_plugin_class_finalize( __budgie_unused__ AppIndicatorNativePluginClass *klazz) { } /** * Export the types to the gobject type system */ G_MODULE_EXPORT void peas_register_types(PeasObjectModule *module) { appindicator_native_plugin_register_type(G_TYPE_MODULE(module)); /* Register the actual dynamic types contained in the resulting plugin */ appindicator_applet_init_gtype(G_TYPE_MODULE(module)); peas_object_module_register_extension_type(module, BUDGIE_TYPE_PLUGIN, APPINDICATOR_TYPE_NATIVE_PLUGIN); } budgie-indicator-applet-0.5/src/plugin.h000066400000000000000000000045751324166217500203320ustar00rootroot00000000000000/** * Copyright (C) 2016-2017 David Mohammed * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #pragma once #include G_BEGIN_DECLS typedef struct _AppIndicatorNativePlugin AppIndicatorNativePlugin; typedef struct _AppIndicatorNativePluginClass AppIndicatorNativePluginClass; #define APPINDICATOR_TYPE_NATIVE_PLUGIN appindicator_native_plugin_get_type() #define APPINDICATOR_NATIVE_PLUGIN(o) \ (G_TYPE_CHECK_INSTANCE_CAST((o), APPINDICATOR_TYPE_NATIVE_PLUGIN, AppIndicatorNativePlugin)) #define APPINDICATOR_IS_NATIVE_PLUGIN(o) \ (G_TYPE_CHECK_INSTANCE_TYPE((o), APPINDICATOR_TYPE_NATIVE_PLUGIN)) #define APPINDICATOR_NATIVE_PLUGIN_CLASS(o) \ (G_TYPE_CHECK_CLASS_CAST((o), \ APPINDICATOR_TYPE_NATIVE_PLUGIN, \ AppIndicatorNativePluginClass)) #define APPINDICATOR_IS_NATIVE_PLUGIN_CLASS(o) \ (G_TYPE_CHECK_CLASS_TYPE((o), APPINDICATOR_TYPE_NATIVE_PLUGIN)) #define APPINDICATOR_NATIVE_PLUGIN_GET_CLASS(o) \ (G_TYPE_INSTANCE_GET_CLASS((o), \ APPINDICATOR_TYPE_NATIVE_PLUGIN, \ AppIndicatorNativePluginClass)) struct _AppIndicatorNativePluginClass { GObjectClass parent_class; }; struct _AppIndicatorNativePlugin { GObject parent; }; GType appindicator_native_plugin_get_type(void); G_END_DECLS budgie-indicator-applet-0.5/update_format.sh000077500000000000000000000005631324166217500212560ustar00rootroot00000000000000#!/bin/bash CI_EXCLUDES="! -path */gvc/* ! -path */src/imports/natray/*" # Ensure we're formatted everywhere. clang-format -i $(find . $CI_EXCLUDES -name '*.[ch]') # Check we have no typos. which misspell 2>/dev/null >/dev/null if [[ $? -eq 0 ]]; then misspell -error `find . $CI_EXCLUDES -name '*.[ch]'` misspell -error `find . $CI_EXCLUDES -name '*.vala'` fi