Home Uniquely NZ Travel Howto Pauline Small Firms Search
More Spices for Cinnamon - Applet Development

Contents


Introduction

This is one of a series of pages started over 10 years ago. This page, like many others, started as a how I did it story with a lot of detailed information on my 5 primary applets in the form of a diary.

The Stopwatch Applet is of particular interest as it was not only intended to be useful in its own right but is also intended to provides a 'tutorial' framework for other more complex applets with many sections of code reusable and fully commented. One useful example is that it provides a sample Settings Screen and a 'standard' right click (context) menu which opens the Settings Screen and a Housekeeping submenu accessing help and a version/update files (which live in the applet folder). It also shows how to run the gnome system monitor program in case you want to find out how much machine power this applet is using at various update rates. Items with a ++ in the comment are not specific to this applet and may be useful for re-use.

Note: The Stopwatch Applet was recently 'emhanced' to implements changes proposed by @100k (Ɓukasz Dobrowolski) in and uses new and extra code provided by him to implement his suggestions. You may wish to back off to version 2.1.0 if you use the applet as a 'tutorial' or 'framework' by checking out the earlier commit in git for the more basic version.

It was then extended to have additional how you should do it information for the newcomer with sections on the main 'tools' I use and a collection of Snippets of JavaScript for Applets used in all my applets. Finally sections have been added covering the changes and additions needed as Cinnamon has itself developed over the and successive versions. These final sections cover topics such as the Localisation in Applets, Converting applets for Vertical panels, Checking if "Dependencies" are loaded and handling differences in Cinnamon versions by version checking or the the inbuilt Cinnamon Extension Versioning.

My Applets - largely a 'diary' of their development

The Network Usage Monitor with Alerts Applet

June 17th 2013

This is my first contribution to Cinnamon Applet Development and is a tool for efficient use of 'Mobile Internet' using primarily the 2G, 3G and ultimately 4G mobile telephone networks but also Wifi Hotspots and other sources where there are data limits applied. It makes use of some of the techniques and code from the original Network Speed Monitor (NSM) project by adreadec who, on 22nd May 2013, announced the project was being discontinued and that any developer who wanted to continue development was welcome see - see https://github.com/andreadec/cinnamon-applet-netspeed. The major difference is that the NSM was designed to continuously display the speed of 'fixed' connections (ethernet and wifi) whilst the new applet is extended to deal with 'mobile' connections using mobile internet dongles and bluetooth connections to phones and the Point to Point Protocol (ppp) and the primary purpose is to monitor data usage on a variety of timescales.

Lets first consider what is needed with a mobile internet connection and how it differs from a home broadband or internet cafe connection. Firstly the speed can be very variable and it is dependent on the signal strength and area. It can vary from under 2KB/s in a rural area with GPRS (2G) coverage through 3G to over 300 KB/s with HSPA or HSPA+ in a city centre. At the higher rates ones data allowance can disappear very fast if one connects to a site which, for example, involves video. The second difference is that the cost is for data not time. In the UK one may be talking at least 500 Mbytes per month but much less when roaming or on an ad hoc Prepay daily allowance when 5 - 25 mbytes/day is more typical. One has to be able to take into account that several machines may be sharing the same data allocation with a Mobile Wifi (Mifi) box or by using a phone/dongle in turn.

So the requirements that I see for mobile internet are:

  1. Continuous indication of upload and download speeds so one can judge what use is appropriate.
  2. Continuously updated total upload and download on and during hover to monitor usage instantly and continuously.
  3. Flexible alert function for current connection so a fine level of control can be maintained - for example by changing the background colour of the applet, a notification or sound.
  4. Cumulative data usage monitors - several to allow monitoring of wifi and ppp connections and different timescales.
  5. Ability to update as well as reset cumulative totals to reflect actual use from provider and use on shared machines.

The Network Data Monitor does satisfies all of the requirements above. The left (usual) click gives a display of information and the right click is used for some display and selection function but most of the setup is done using the new Cinnamon Control Panel. The Applet has a continuously updating display of the upload and download rates and hovering shows continuously updating upload and download totals for the current connection. The following images show the various features popup menus and the settings panel.

Screenshot
Screenshot
Screenshot Screenshot
Screenshot

Typical Use of the Network Usage Monitor with Alerts Applet

Lets look at an example. I have a data allocation of 500 mbytes per month on my Prepay tariff which is sometimes shared between two machines when we are traveling in the UK so I normally set up NUMA with a 'maximum data' warning set to of the amount of data I am prepared to use on each connection. I set the Red Limit to be 25 mbytes which is a bit over the average I can use but low enough that it is not a problem if I reach it. I set an Alert (Orange level) at about 40% so I get an early warning and I can easily use the slider to increase that at any time. These settings mean I am rarely going to get any surprises even if I am on a very fast connection and accidentally start a video.

I am also interested in the total data I have used out of the 500 mbytes per month and on the first day of the new allocation I set one of the cumulative counters to that interface and to zero. During the month I can periodically check one the service providers web site and correct the total if required. I can also correct for usage on another machine. As I have various Dongles and accounts I can use different counters for each. I can make sure I know what I have done by using the 'comment' associated with each to record dates and values of resetting and what it refers to.

There is a comprehensive of settings screen using the inbuilt settings in the latest version of Cinnamon. It can be accessed by Cinnamon Settings -> Applets, highlight and click Settings or directly from the right click 'context' menu. You can enable and set up Alerts and Cumulative monitoring as well as adjusting the frequency and resolution of updates in the panel and the 'default interface if the is no active connection at start-up.

Initial Input for Cinnamon Spices Entry

Screenshot

Summary

IconThe Network Usage Monitor with Alerts Applet (NUMA) enables one to continuously display the speed and data usage on a selected interface. It is intended to make monitoring of mobile connections by USB Mobile Internet Dongles, through phones by bluetooth and by Mobile Wifi (MiFi) units easy. It has also been extended to monitor much larger data usage figures for use for broadband users paying by the gigabyte. To these ends, a maximum data and easily changed Alert level can be set for the current connection. There are also a number of cumulative data monitors to track total usage with offsets and corrections as required. It initially built on the Network Speed Monitor Applet project by adreadec who discontinued that project.

Requirements:

sudo apt-get install sox libsox-fmt-mp3 zenity gir1.2-gtop-2.0 vnstat vnstati

Installation:

Features:

Additional Configuration

The display width, justification and font details are set using an external Cascading Style Sheet (.css) file which is in the main folder (usually ~/.local/share/cinnamon/netusagemonitor@pdcurtis/stylesheet.css).

The settings in this css file govern the width of the Applet and the space taken by the font. Changes may be required with some themes to avoid the display width being exceeded which leads to jitter with high network speeds and resolutions or to allow a reduced size width to save panel space. Make a backup as the file will be overwritten if an updated version of the NUMA is installed

From version v18_2.3.0 there are two Shell script files which are run as options when the data usage limit is exceeded and are in the main folder(usually ~/.local/share/cinnamon/netusagemonitor@pdcurtis. One is for users to modify and is called alertScript and the other is called suspendScript and is used to suspend the machine where some addition fine tuning could be done by the user. These can be accessed for editing and run to test from the advanced section of the Context Housekeeping Submenu. They use two additional programs for playing warning sounds (Sox) and providing interactive warning boxes (Zenity) . These will probably need to be installed using your Package Manager or running in a terminal:

sudo apt-get install sox libsox-fmt-mp3 zenity gir1.2-gtop-2.0 vnstat vnstati

For completeness the above also installs/updates all the other programs required by the latest versions of NUMA.

========= End of Input for Cinnamon Spices Entry =============

NUMA Development Version v18_2.1

Addition of output from vnStat and vnStati

Screenshot

I have added output from vnStat, see above. It uses vnstat which produces a variety of of displays of traffic statistics which it collects continuously in the background using a daemon. The output here is via graphic produced by vnstati. The output displayed matches the selected interface at present and there are many possible formats of which I have chosen one displaying today's, yesterday, the months and the last months traffic.

The vnstat and vnstati programs have to be installed using the one of the package managers in Mint. I usually use the Synaptic Package Manager or the terminal for installing software but it is not installed by default. To install them in a terminal do:

sudo apt-get install vnstat vnstati

Once they are installed the vnstat daemon is automatically started and runs in the background collecting data with a very small overhead. vnstat is a command line program with many options and vnstati produces output with a similar set of options but in the form of an image which can be used to display information on a web site or, as here, in an applet. The output is not very pretty but it's comprehensiveness more than makes up for that.

The technique used has been 'borrowed' from an Applet by Clem but for some reason the display can only be removed by a Cinnamon restart. This can be achieved by Alt F2 and enter r then return. It seems that way the item is added to the menu does not allow the normal API method for clearing all menu entries ( this.menu.removeAll(); ) to remove it - this also means it always ends up at the top of the menu. A similar technique seems to be used in the sound applet for the CD cover which does not have the problem and I have done the same as used there and used an extra box from which I can at least remove the actor giving a null display and avoid having to do a Cinnamon restart.

Adding a Compact Display using total rather than upload and download rates

This has been requested by a user and a development version has been implemented. It can be enabled and disabled in the Settings Panel or on the right click menu. I have also changed the U: and D: to ↑ , ↓ arrows and to ⇵ for the total to save space. This has required a significant change in the way the display of data in the applet is formatted.

The original Network Speed Monitor avoided jitter due to varying widths of the display by using formatting in a cascading style sheet file (.css file) to define a minimum width for the up and down numbers displayed. It does not seem to be possible to remove one of the two 'actors' which are added to the applet without an applet reload by a user logout or a cinnamon restart so I leave both in place but I use a 1 pixel length for the second number when in compact mode. The minimum length of the first number is still set in a cascading style sheet but not for the second number and instead the overall applet width is set to allow sufficient space. The defaults should be fine with most themes and with up to two decimal places shown but the .css file can be displayed and edited using a housekeeping sub-menu within the right click menu and the applet width can be set on the Settings Panel if fine tuning is required.

Addition of a Housekeeping and System Submenu to the Context Menu

This currently has three items:

Facilities added in NUMA Development Version v18_2.2.

Addition of responses when the data usage is exceeded

This is another major increase in utility as a number of actions can be taken when the current Data Usage Limit is exceeded. The existing facilities work well when one is present and watching whilst the machine is in use but I got badly caught when I had to use the Desktop with a mobile connection whilst the broadband connection was faulty. Unfortunately the desktop was set up to automatically download updates in the background ready to install at my convenience. I returned to the machine an hour later to find 192 Mbytes had been downloaded leaving me with 70 mbytes for three weeks! It is easy to detect the point where the limit is exceeded - a single line of code runs a function but what should it do? Killing all Network traffic sounds easy (eg via ifconfig) but it normally needs an administrative password as there could be other users on a machine and I have not yet found a foolproof way through Network Manager/Cinnamon.

The only reasonably safe way of handling an unattended machine which minimises risk of data loss is to suspend the machine. It, of course, also needed wrapping up with a highly visible warning, with a timeout before suspending, and a display of information which was very visibly when the machine is woken up again. I am sure it is possible to achieve highly visible notifications with timeouts in Javascript within cinnamon but I have made use of a small utility called zenity which allows one to put up warning boxes and much more from shell scripts so I decided to make the more complex responses to think of as crisis handling when a data limit is exceeded. Crisis may sound a strong word but consider a typical Pay as You Go data situation - the first 500 Mbytes costs effectively £10 for the month. When you exceed that you pay £1 per day with up to 25 Mbytes however if you exceed that it jumps to £1 per Mbyte and that to my mind is a crisis as you can burn 1 Mbyte in a few seconds in an area with mobile broadband!

So what is the end result? I have added an extra check box to the Settings to enable a Response to a Exceeding the Data Usage Limit - this is the limit set for the current connection which is being monitored and changes the applet orange at an alert percentage and red at the same time as the response is triggered. It happens once as the at the time it is exceeded. I have also added a drop down list of actions to chose from:

  1. Do nothing other than put up a standard Cinnamon Notification - this displays for 5 seconds or so and ends up in the notification tray - very easy to miss.
  2. Display a high priority Notification - this displays on to of other windows until you clear it but does not go into the notification tray - still easy to miss from a distance.
  3. Display a full screen Modal Dialog - this is techie term (look it up on Wikipedia) and the result is the whole screen is blacked out with an information box and button to clear it in the middle and uses the internal capabilities of Cinnamon. It is impossible to miss if you are at or close to the machine.
  4. Run a shell script which lives in the applet folder and is called alertScript - this can be customised by the user and the example plays a system sound file for 6 seconds (using Sox) , puts up a warning box using Zenity and sends a standard notification so you have a record in the notification tray. It needs Zenity and Sox to be installed to work. This is also difficult to miss, especially if you have sound turned on.
  5. Suspend the Machine after a brief period during which you can abort. This is also implemented by a script (suspendScript) so the user can fine tune it but the version provided uses Zenity for the warning message which has a 30 second timeout to allow you to abort. Another message is put up before suspending which should be on display when you wake up the machine. The suspension is carried out via the dbus mechanism and does not need an administrative password or confirmation. The only potential problem is that some older machines do not suspend cleanly and you may have to suspend to disk (hibernate) on some or even do a shutdown which could any files you are working on but in most cases you can be sure that you will not be using expensive data within 32 seconds (or the timeout you chose) of the data limit being exceeded so you can go right up to the wall.
  6. Disable Networking for all connections managed by the Network manager (version 2.3.0 and higher). This puts up a warning message and you can abort for a short period by clicking the Applet - not the OK button on the warning screen. It leaves a highly visible Modal Dialog after disabling the Applet so a user away from the machine can not miss it on his return. This technique does not work for connections not made by the network manager, for example, by GnomePPP to a Bluetooth telephone - the suspend approach is favoured in that case. The delay during which one can abort can be adjusted in the Settings screen. Re-enabling Networking is easy and is carried out in the Network Manager Applet.

The new settings screen and Context menu look like this for version v18_2.2:

Screenshot Screenshot

To aid writing and testing the scripts I added a number of items to the Housekeeping and System Sub Menu and I have decided to leave them in place to make it easy for any user who wants to customise the responses via scripts so the following items have been added to the existing 3 items.

  1. Open alertScript for editing
  2. Open suspendScript for editing
  3. Test alertScript ie run it as you would in a terminal by sh alertScript
  4. Test suspendScript
  5. Test the crisis management function - this calls the function which is normally called as the data limit is exceeded because testing otherwise needed changing limits and having a data flow.

They will probable remain but may be hidden by another checkbox from users who do not need these advanced capabilities.

Facilities added in NUMA Development Version v18_2.3.2 (Beta).

I have finally found a way to make a call to the Network Manager Client (NMClient) which immediately disconnects the network.

This only disables connections managed by the Network Manager but does not include ppp0 connections made, for example, by GnomePPP. The only way to handle automatic data limiting in the case of independent connections is via the suspend script

There is an ability now built in to abort the network disabling for a short period. My approach is to carry out the Network Disabling via a function called by a Mainloop.timeout_add_delay. This works in the background delays the call to the function giving the user a warning message and an option to abort. This clears a flag which is checked in the function which is started after the delay. The flag is cleared by clicking the Applet before the timer has completed. I have set it up so the timeout is a variable so the delay can be adjusted and the messages via zenity reflect the value of the delay and I plan to add it to Settings. It also needs to leave a meaningful 'modal alert' which can not be missed by users of unattended machines after the Network has been and a short message to confirm the abort was successful.

During the final optimisation of the user interface I have added some extra Settings

  1. An adjustable Delay time when Disabling the Network
  2. A flag to chose whether to display the development Housekeeping Functions in the Context menu
  3. A flag to chose to play a sound file as well as a visible alert
  4. The path and filename of the alert sound file

Facilities added in NUMA Development Version v18_2.3.6 (Beta).

ScreenshotThe backgrounds have been improved for themes with a light panel colour and rounded corners added to give a more pleasing appearance. This has been tested with a number of light themes such as Void, Elune and Baldr, gray backgrounds such as Cinnamon and Glass Mint and dark/black backgrounds such as Minty G, Tyr jord and Faienca+.

By request, the new backgrounds are set using the css stylesheet (stylesheet.css in the applet folder) so they can be customised to match the theme even more closely.

A minor bug fix as the Context Menu was not always rebuilt after adding or removing advanced functions submenu so a cinnamon restart was required.

19th February 2014

NUMA - problems with segfaults in Cinnamon -> v20_2.3.17

It has been recently reported that there may be an interaction between NUMA and the latest Cinnamon/Mint which are causing "Random Crashes : Segfault by libgio-2.0.so" . I have never seen any segfaults (or crashes in Nemo which may be related) with any version of NUMA running on machines which were running the current version of NUMA (at the time) and Cinnamon on machines which are using Ubuntu overlayed with Cinnamon (not higher than Ubuntu 13.10). I finally managed to reproduce the crashes on my machine running Mint 16 Petra when heavily loaded (firefox with many open tabs and several programs running under WINE and internet transfers taking place). Even then they were very intermittent, once every few hours being typical. My Simple Timer and Bumblebee And Nvidia Display (BAND) applet both use a lot of common code in the update loops and menu generation and cinnamon-settings API show no problems. I re-ran the latest settings .json file through the online tester and it was valid.

I have also run the current version of my applet on the same machine under Linux Mint Cinnamon 15 32-bit with kernel 3.8.0-19 and Cinnamon Version 2.0.14 from the gwendal-lebilhan-dev/cinnamon-stable PPA and that also showed no sign of crashes after 24 hours continuous operation. The system is part of a triple boot system and the Mint 15 option was last updated fully on 19 December 2013. This was not conclusive but was highly indicative that the issue (regression) is somewhere in Mint 16 (obviously including all the underpinning Ubuntu).

What was required was to find out what in the NUMA applet is tripping the problem in Mint 16 to see what can be done as a work around. I considerably narrowed the field in that the precursor to NUMA for Cinnamon 1.6 (ie without any use of the Settings API) shows no problems. I am also now fairly convinced that the nemo segfaults I have been suffering ( https://github.com/linuxmint/Cinnamon/issues/2835 ) are also a result of the same problem - I thought I had eliminated applets but was unaware they could still be partially active even after removal from the panel - a fault I will correct in all my applets using mainloop 'timers'. I have tested various previous versions until I had bisected down to a small series of changes which seemed to be causing the problem.

To cut a long story short the bisection seems to show a problem occurs between versions 1.7.2 and 2.1.0 where there are significant change is in how cumulative counters are updated. Instead of only updating counters with information from the monitored interface it was more general and would update regardless of the interface which was being monitored. This involved a series of consecutive calls to GTop.glibtop_get_netload() and used built in error correction in the system routine rather than explicit checks in NUMA. It initially seemed most likely that the latest version of code in Mint 16 occasionally crashes with invalid inputs - what counts as invalid is yet to be determined and I put some additional checks in place. That seemed to reduce the errors, particularly in nemo segfaults which dropped to zero but there were still occasional cinnamon segfaults indicating that was not the whole story. The other change was that the cumulative data is stored in a bidirectional settings value which was used in read and write mode within a single expression and tests reason is obscure but further tests indicated that when there was only a single write per update cycle there were no segfaults whilst extra consecutive calls to update the cumulative counters show problems. I also tested using values which were explicitly floating point numbers with no significant change.

I had intended to make some changes to how cumulative data monitoring was handled. The data usage value was changed or reset using a bidirectional value which was updated by the applet as well as from the settings program. This caused problems when changing/resetting it from the settings screen as changes could be 'pushed back' by updates from the applet. The cumulative data could also be updated by interfaces which were not currently being monitored - this had seemed desirable but is confusing and I can not see any circumstances when it would actually be useful. I have therefore taken the opportunity to update the cumulative data usage monitoring. It only uses the settings screen to turn each of the three monitors on and define their interfaces. They are each reset by a right click (context) menu item and the time of reset is shown in the left click screen along with the current value - much simpler and more fool proof. The whole section has been re coded to only use a single write of a 'settings' value per cycle and a single system call to GTop.glibtop_get_netload() . In addition the settings value has been changed to a floating point 'generic' function. My best bet is that the problem was with multiple read and write calls to the systems settings which, of course, involved read and writing to the same file and this gave some obscure race condition but all the other possibilities I can think of have also been taken care of. Testing can only prove the existence of bugs and never prove they do not exist but it is promising this has been run with the update rate speeded up ten fold for a long period without segfaults in Cinnamon or Nemo when previously they would occur within a few hours.

UPDATE Tests under Mint 18 with Cinnamon 3.07

I have run the previously buggy v18_2.3.7 modified for a x10 update rate for 56 hours under Mint 18 with Cinnamon 3.0.7 without any segfaults in any programs. This was simply achieved in a couple of minutes by creating a new Git 'testing' branch from from tag NUMA-2.3.7 . This version was checked by the combination of searching the last two kernel log files and dmesg using:

grep seg /var/log/kern.log
grep seg /var/log/kern.log.1
dmesg | grep seg

This is very indicative that the problem has issue in Mint 16 has been successfully resolved in Mint 18 with Cinnamon 3.07 and this result has beenreported in issue "Random Crashes : Segfault by libgio-2.0.so" after the test time under heavy machine usage.

Version v20_2.3.17 (Uploaded 20 March 2014)

This has an addition belt and braces change and has the update cycle split in two with the writes to the cinnamon-settings API therefore separated by at least half a second from everything else. This finally seemed to be a satisfactory workround for the problem until it is corrected by the Ubuntu or Cinnamon teams.

Version v20_2.4.0 (Uploaded 20 March 2014)

Version v20_2.4.1

Version v20_2.4.2 - (Uploaded 6 May 2014 and current until 16 August 2016)

Display of Header inhibited when no Cummulative Data being displayed - cosmetic improvement.

This was the main version for Mint 16 and Mint 17.x. Versions v30_3.0.3 and higher should be used with Mint 18/Cinnamon 3.0.x which also brings in a number of other useful enhancements.

Development Versions (not uploaded to Cinnamon Spices until v30_3.0.3)

Versions v20_2.4.3.x

Restart of development of version where multiple instances will be available for sophisticated users and complex applications. Note hand crafting of .cinnamon/configs/netusagemonitor@pdcurtis required unless completely uninstalled, Cinnamon restarted and reinstalled with loss of all existing settings. This is because of a Cinnamon issue detailed at https://github.com/linuxmint/Cinnamon/issues/3127

2.4.3.0 Multiple instances in metadata.json
Changes to minimise width of applet when not connected to go with multiple instances.
Change to width in stylesheet.css to match
New function to pad and center output to remove jitter rather use styles.
2.4.3.1 General tidy up of commented out code
2.4.3.2 Add an offset which is set in settings but is also cleared by reset of usage
Display includes offset when in use.

Currently only available on Cumulative Data Usage 1
Continue tidy up
2.4.3.3 Width padding corrected for display resolution
Offsets on all available Cumulative Data Usage channels
2.4.3.4 Changed space character to \u2007 which has an equivalent width to a number
2.4.3.5 Added a call to buildContextMenu on left click to set up after a connection has changed.
2.4.3 Above all compressed into a single commit from above branch created in development branch
2,4.4 Removal of some commented out text
2.4.4.1 Changes in padding and in width calculation for compact display
2.4.4.2 Modified functions for formatSpeed and formatSentReceived to extend to [B,] GB and TB and make consistent

Version v20_2.5.0 - Development Version

Version with single instance but all other enhancements as above in preparation for upload when Mint 17.1/Cinnamon 2.4 is available.

max-instance changed in metadata.json to 1 to hopefully avoid need for hand crafting of .cinnamon/configs/netusagemonitor@pdcurtis.

The file .local/share/cinnamon/applets/netusagemonitor@pdcurtis/metadata.json can be however be edited to increase the number of instances to say 3 but you will need to completely uninstall before making this change or be prepared to make changes in .cinnamon/configs/netusagemonitor@pdcurtis

See https://github.com/linuxmint/Cinnamon/issues/3127 for why a simple update does not work and complete uninstalling is required to switch between single and multiple instance versions .

Version v20_2.6.0

This version supports Android Tethered Connections over Bluetooth. First we need to know a bit of background about the connections used by Android for Bluetooth Tethering

Background on the Connections and Interfaces used by Android for Bluetooth Tethering - PAN, NAP and BNEP

The Android Bluetooth tethered connection uses a Personal Area Network (PAN) which is a computer network used for data transmission among devices such as computers, telephones and personal digital assistants. PANs can be used for communication among the personal devices themselves or for connecting to a higher level network and the Internet. A Bluetooth PAN is composed of up to 8 active devices in a master-slave relationship (a very large number of devices can be connected in "parked" mode). The first Bluetooth device is the master or in this case the Network Access Point (NAP), and all other devices are slaves that communicate with the master. The communication protocol is the Bluetooth Network Encapsulation Protocol (BNEP) which is used to transport common networking protocols over the Bluetooth media such as IPv4 and IPv6. The packet format is based on Ethernet.

The Bluetooth manager detects that the Android device supports PAN/NAP and, by ticking the box, creates a connection for the Network Manager. The Network Manager (in the form of the applet) makes this available but the support is incomplete. As mentioned above one easily ends up with duplicate connection which have to be deleted from the terminal as root. The connection is also identified by the Bluetooth address and it delivers this rather than the actual connection interface which is bnep0 and is displayed as a Mobile Broadband Connection which is an approximation to the truth! This causes a problem with my NUMA applet which depends on the interface delivered by the Network Manager so I have had to add an exception as I have with the ppp0 interfaces used by Mobile Broadband connection.

This causes a problem with my NUMA applet which depends on the interface delivered by the Network Manager so I have had to add an exception as I have with the ppp0 interfaces used by Mobile Broadband connection to cover bnep0 interfaces. In essence:

Added support for Android Bluetooth tethered connections which use device bnep1 under Mint 17 ny duplicating the code for ppp0 using bnep0 in three places. This is required because selecting the active bluetooth connection which looks like 12:34:56:78:90:12 in the network manager does not work. It ought to be possible to use bnep0 whenever the active interface contains semicolons but if it aint broke don't fix it! In addition there is no reason to believe that the shortfalls in the Network Manager will not be fixed and break any clever work around.

Version v30_3.0.3 Uploaded to Cinnamon Spices 1 August 2016

This version responds to changes in Mint 18 and Cinnamon 3.0 requiring significant modificatios.

It includes the changes in development version v20_2.5.0 so it may require a complete uninstall and reinstall when upgrading from the earlier version v20_2.4.2 available from the Spices web site.

Mint 18 has changed to use of systemd instead of upstart to initialise the system, for system calls and for daemon managment. This results in a change in the way suspend is called in the suspendScript script file.

Mint 18 no longer has gedit installed as the default text editor and uses xed instead. The editor is called to give access to the changelog, help script and css and script files. A mechanism to select the editor based on Cinnamon Version is being included. Part of the code has already been developed for the Stopwatch applet.

Other major enhancements in the v30_3.0.x series over the last uploaded version (v20_2.4.2) are in:

Cumulative Data Usage Offset: An offset is now available in settings which is also reset by a right click 'Reset Cumulataive Usage' for the three monitored interfaces.

The date of the last Cumulative Data Monitor Reset is now displayed.

Support of Android Tethered Connections over Bluetooth (See v20_ 2.6.0 for details).

Support of multiple instance - available but requires edit of metadata.json to set to more than one. Note this change may require a complete uninstall and reinstall (see v20_2.5.0 for more details)

Version v30_3.05 Available on GitHub as Beta

I have received a request to update the applet to handle users with high data allowances better, broadband providers often have monthly allowances of 50 or more Gbytes.

Currently the applet handles displays of up to Terabytes but the settings for Alert Levels and Cumulative offsets are given a max of 5000 Mbytes. This avoided the problem of a Gbyte usually being 1024 Mbytes.

I have increased the limits to 200000 Mbytes in this version which is actually 195.31 Gbytes and as a temporary fudge changed the displays such that 1 Gbyte is 1000 Mbytes and 1 Terabyte is 1000 Gbytes whilst considering alternative ways to handle a wide range without making the Configuration window even more complex such as drop down boxes to specify Mbytes, Gbytes or Terabytes.

The cumulative data display has been refined to better handle Gbyte and Tbyte usage levels.

This version is available on GitHub https://github.com/pdcurtis/cinnamon-applets (15th August 2016)

Version v30_3.06 Uploaded to Cinnamon Spices 25 August 2016

I finally decided to add a single drop down style widget to specify choice of units of Mbytes or Gbytes for limits and offsets in configuration window. Unfortunately there seems to be no way to put several widgets on the same line. Maximum Limits and Offsets still remains at 200000 Mbytes/Gbytes as appropriate so settings can be entered in Mbytes to give a higher resolution. Fudge for Gbytes and Tbytes no longer required and removed

This version is available on GitHub https://github.com/pdcurtis/cinnamon-applets

Changes to Spices implementation and use of Github by Cinnamon in January 2017

This has caused some major changes in the way of development of spices and there have been a number of changes which have not directly effected the major functions of my applets but have changed some of the implementations to harmonise with other applets.

Further Significant changes since January 2017

3.1.1

Additional PopupMenu.PopupMenuSection added as per an easy and elegant suggestion from @collinss and @Odyseus so 'standard' context menu items are retained when the menu is refreshed.

3.2.1

Harmonise with code writen by author for vnstat@cinnamon.org

3.2.2

Support new facility on Cinnamon Spices Web Site to display a CHANGELOG.md

Screenshot

Simple Stopwatch Applet

This is a very simple to use Stopwatch Applet which can have multiple instances in the panel. In its basic form it is controlled completely by clicking the Applet - the first click starts it and it displays an increasing time, the second stops it and a third click resets it ready for the next time. The display starts with minutes and seconds and maintains a constant width, for example two minutes and 7 seconds is 02:07 to avoid jitter. If the time exceeds one hour it goes to 01:02:03, over a day and the days are displayed in the tooltip. To aid knowing the status at a glance it is black when Ready, dark green when Running and dark orange when Paused and the tooltip always displays the name of the instance, the status, time and what the next click does. See below for the display which is set against the backdrop of the Settings Screen. Screenshot

The Settings Screen can be reach from a right click as well as Cinnamon Settings -> Applets. It enables you to:

The Right Click (Context) menu has options to:
Screenshot

And that is about it - the help file is hopefully redundant as there is always full information when you hover over options on the Settings screen or the Applet itself.

There is one additional attribute. The applet was not only intended to be useful in its own right but it is also intended to provides a 'tutorial' framework for other more complex applets with many sections of code reusable and fully commented. One useful example is that it provides a sample Settings Screen and a 'standard' right click (context) menu which opens the Settings Screen and a Housekeeping submenu accessing help and a version/update files (which live in the applet folder). It also shows how to run the gnome system monitor program in case you want to find out how much machine power this applet is using at various update rates. Items with a ++ in the comment are not specific to this applet and useful for re-use.

Additional Notes:

Changes in Development Version v18_1.1.2

ScreenshotThere was a quick fix to the background colours to use transparency so they work with light and dark themes and I have added a radiused border to the background colours and made them configurable via a stylesheet (stylesheet.css in the applet folder) with an extra menu item added to open the stylesheet. This has been tested with a number of light themes such as Void, Elune and Baldr, gray backgrounds such as Cinnamon and Glass Mint and dark/black backgrounds such as Minty G, Tyr jord and Faienca+. The situation where the day count has been exceeded is now shown by a red border rather than background so that running and paused are separated.

ScreenshotThe screenshots show 4 Instances , from left to right, the first is Ready, the second is Running, the third Paused and the fourth has been running for 10 days so it shows the red border and the tooltip showing the full information with the settings screen behind. The top theme is the new Minty G and below shows them on the very beautiful Void themes panel.

v20_1.2.0

Inhibit counter updates after counter removed from panel - this is discussed in the NUMA section but in essence removing an applet from the panel does not automatically stop and timing loops. So if you try an applet and do not like it or one is seeking bugs during development one has to not only restart Cinnamon but also reboot the machine to completely remove traces. I added the code here as this applet is also intended to provides a 'tutorial' framework for other more complex applets with many sections of code reusable and fully commented.

v20_1.2.1

Modifications for Cinnamon 2 by adding cinnamonVersion to settings to allow Cinnamon Version to be specified and thus inhibit the extra menu entry appearing in settings when it was automatically added to Cinnamon 2.2. A short term fix until I found a good way to obtain the Cinnamon version in use.

v20_1.2.2

Change 'Settings' to 'Configure..' and place after housekeping for consistency - purely a cosmetic change

v20_1.2.3

Pick up Cinnamon Version from environment variable CINNAMON_VERSION rather than settings window.

Having found where the environment variable is stored it was still a problem to write or find a routine to reliably compare version numbers which come in many variants. Mine is closely based on code by Alexey Bass (albass) and is sufficiently general to take account of the variations which the Cinnamon team might introduce.

It is another code snippett which others may wish to use and they should include the reference to Alexey Bass as well as myself. I have lost the original reference to where I found it but a search shows it also appears at https://gist.github.com/alexey-bass/1115557 with more comprehensive comments on how to use it.

// Compare two version numbers (strings) closely based on code by Alexey Bass (albass)
// Takes account of many variations of version numbers including cinnamon.
versionCompare: function (left, right) {
if (typeof left + typeof right != 'stringstring')
return false;
var a = left.split('.'),
b = right.split('.'),
i = 0, len = Math.max(a.length, b.length);
for (; i < len; i++) {
if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
return 1;
} else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
return -1;
}
}
return 0;

2.0.0

Changes for Mint 18/Cinnamon 2.8

Use Cinnamon version to choose text editor (gedit -> xed) to view changelog, help etc

Changes to Spices implementation and use of Github by Cinnamon in January 2017

This has caused some major changes in the way of development of spices and there have been a number of changes which have not directly effected the major functions of my applets but have changed some of the implementations to harmonise with other applets.

By 2.1.0 (May 2017)

ScreenshotBAND (Bumblebee And NVidia Display) Applet

Screenshot

This is an applet I am writing to get round the problems of the existing nVidia/Bumblebee Monitoring Applets, in particular that of additional power usage when the nVidia Card is not in use. The screenshot shows two sample programs set up in the left click menu and the DGPU is on so the temperature is displayed. You will note that there are two additional and useful applets to the right of BAND.

It either displays the nVidia GPU temperature when running or a message that the DGPU (Discrete Graphics Processor Unit) is off. It interrogates bbswitch to get the status and when the card is on it uses nvidia-settings to get the GPU temperature. It uses the same fudge as gputemperature@silentage.com to run nvidia-settings asynchronously and writes the output to a temporary file in applet folder. It currently has a delay of 20 seconds on loading before it gives information as bumblebee and bbswitch seem to take a while to come up at boot time. The right click menu gives access to the nVidia Settings program, the System Monitor Program and the Power Statistics Program without needing a terminal.

'Internals' of the BAND applet

The code to find out if bbswitch has turned the GPU on or off is:

cat /proc/acpi/bbswitch

This is read by code similar to this:

try {
this.bbswitchStatus = GLib.file_get_contents("/proc/acpi/bbswitch").toString();
this.bbswitchStatus2 = this.bbswitchStatus.substr( (this.bbswitchStatus.length - 2 ),1 );
// Checking for N as last character in string ensures bbswitch is present and ON before nvidia-settings run
if (this.bbswitchStatus2 == "N") {
this.bbst = "ON";
}
else {
this.bbst = "OFF";
}
// This catches error if bbswitch and hence bumblebee is not loaded
} catch (e) {
// global.logError(e); // Comment out to avoid filling error log
this.bbst = "ERROR"
this.set_applet_label("ERROR" );
this.set_applet_tooltip("Bumblebee is not installed so applet willl not work");
}

Note that one needs to catch errors in case the applet is loaded into a system without bumblebee installed - in this case the applet label is set to "ERROR" and the tooltip to "Bumblebee is not installed so applet willl not work" This is not done in the RC but is in the final version.

The code to find the GPU Core Temperature is:

optirun -b none nvidia-settings -q GPUCoreTemp -t -c :8

Future plans include checking whether the laptop is running on battery and inhibiting or warning when a program is about to be started using via optirun and use the nVidia graphics. The power status can be found via a call to nvidia-status in the same way as the GPU temperature.

optirun -b none nvidia-settings -q GPUPowerSource -t -c :8

You can also get a very comprehensive listing of the nVidia Status by:

optirun -b none nvidia-settings -q all -t -c :8

This could be used to give a more comprehensive left click menu but I prefer to use nVidia-Settings itself and reserve the left click for running programs using Optirun

It is not trivial to use these calls as they involve a long response time so nvidia-settings has to be called asynchronously. The obvious way is an asynchronous call to a script which writes the output to a file which can then be read very quickly. The mainloop timer is used to ensure that the operation has completed before the file is read. The gputemperature@silentage.com applet has a fudge to run nvidia-settings asynchronously and writes the output to a temporary file in applet folder without using a script which I have adapted in BAND. Have a look inside the applet.js file in the bumblebee@pdcurtis folder to see exactly how it is done.

It seems that it takes a while for bbswitch and bumblebee to settle after a boot so there is an longer initial delay before the applet starts to display.

The applet is not only useful in its own right but is also based on a ''tutorial' framework for applets - for example it provides a settings screen and a 'standard' right click (context) menu which opens the settings panel and a Housekeeping submenu accessing help and a version/update files and also the nVidia settings program, the gnome system monitor program and the Power monitor in this you want to find out how much resources this applet is using at various update rates. Items with a ++ in the comment are useful for re-use. Using my basic framework this applet was largely completed in hours although idle hands have added extra features!

I am also trialing a version which does not have the 'clever' fudge and instead makes a an asyncronous call to a two line script which runs nvidia-settings with the output sent to a file in /tmp which is then read the same way as the current version. It also needs the file to be initialised when it is in /tmp. It seems more consistent and I prefer code I have written and understand to clever tricks. I will make it available when it has had a little more testing.

Text for Upload and helpfile

The Bumblebee And NVidia Display (Band) Applet is a relatively simple applet I wrote for my new Chillblast Defiant laptop which has an Core i7 Haswell architecture and Optimus technology to switch between the integrated Intel 4600 graphics and discrete nVidia GTX 765M graphics. The switching is done by use of Bumblebee. This Applet allows one to monitor whether the power consuming discrete graphics is on and display the GPU temperature, but only when it is enabled. Monitoring the temperature requires the graphics processor to be turned on every time it is measured - some applets do this all the time and that uses a significant extra amount of power.

The right click context menu gives the ability to easily run the nVidia Settings program without use of the terminal and also the System Monitor and Power Statistics, all useful for monitoring Bumblebee and power consumption which is paramount when using a laptop on batteries.

The standard left click menu provides a configurable list of programs which one can run using the discrete nVidia graphics through Bumblebee - this otherwise requires them to be called through optirun in a terminal or via a modified launcher. This list is configured using the standard applet configuration mechanism available from Cinnamon 1.8 (Cinnamon 2.0 required for this to be on the right click menu). One can also configure the update rate of the applet in settings. Currently there are two examples - glxspheres is a very good test of the speed of the graphics but may need to be installed. The other example is the nVidia Settings program which is also on the right click menu so it can be overwritten. There are 5 'slots' currently and if you do not require a slot set the Display Name to null or leave it completely empty.

The applet requires at least Cinnamon 1.8 and 2.0 is desirable to access the configuration from within the applet. Bumblebee and the nVidia graphics packages obviously need to be installed but no other packages are needed. Installation is standard and the folder bumblebee@pdcurtis is extracted from the zip file to ~/.local/share/cinnamon/applets and then added to the panel.

The current version has improved error checking to ensure bumblebee is loaded and does not fill the error logs with messages when it is not loaded. It now displays ERROR in the panel if bumblebee is not loaded and a message when you hover.

Installing glxspheres

Download VirtualGL (.deb) from: http://sourceforge.net/projects/virtualgl/files/VirtualGL/

Navigate to the folder containing the deb package and install it with:

sudo dpkg -i VirtualGL_*.deb

Run glxspheres:

cd /opt/VirtualGL/bin/
./glxspheres64

In the unlikely event you are running a 32 bit system use glxspheres rather than glxspheres64

ScreenshotnVidia Prime Display Applet

Screenshot

This is a simple applet written originally for my own purposes to enable me to monitor the temperature of the nVidia Discrete Graphics Processor Unit on my laptop.

The Nvivia Prime Display Applet is a cut down version of the Bumblebee applet I wrote a couple of years ago for my Chillblast Defiant laptop which has an Core i7 Haswell architecture and Optimus technology to switch between the Integrated Intel 4600 graphics and Discrete nVidia GTX 765M graphics.

The prefered method of switching with the latest kernels and nVidia drivers no longer uses Bumblebee but utilises Nvidia Prime which is simpler to install and use. This Applet allows one to monitor whether the power consuming discrete graphics is on and display the nVidia GPU temperature, but only when it is enabled as monitoring the temperature requires the graphics processor to be turned on. The Bumblebee applet is still available for those who wish to use Bumblebee, which still has some advantages over nVidia Prime, although it is more difficult to install.

Clicking the applet opens nvidia-settings which allows one to change GPU in the same way as the built in NVIDIA Prime applet which it can replace if panel space is at a premium.

The right click context menu also gives the ability to run the nVidia Settings program as well as the System Monitor and Power Statistics, all useful for monitoring and controlling power consumption which is paramount when using a laptop on batteries.

There is error checking to ensure the switching program bbswith is loaded and does not fill the error logs with messages when that is not the the case. It displays a message of ERROR if it is not found.

The applet requires at least Cinnamon 1.8 to access the configuration from within the applet and has been tested up to Cinnamon 3.0 where it adapts to use xed to display the help and changelog files. The nVidia graphics packages obviously need to be installed but no other packages are essential. Installation is standard and the folder nvidiaprime@pdcurtis is extracted from the zip file to ~/.local/share/cinnamon/applets and then added to the panel.

The latest version has a tick box option on the configuration screen to access enhanced functionality through the Right Click Context Menu. This needs a Cinnamon Restart or log out/in before the change is visible. Currently this adds the glxspheres64 Graphics Processor Test to the menu. glxspheres64 is not installed by default and the VirtualGL package needs to be installed from http://sourceforge.net/projects/virtualgl/files/VirtualGL/ - download the latest version and install using gdebi (should be the default for a right click on the downloaded file). It should run about five times faster when the nVidia GPU is active and is a very good test as to how good your cooling is for both the CPU and nVidia GPU when it is active.

This is fully documented and can be downloaded at https://cinnamon-spices.linuxmint.com/applets/view/259 and is on Github at https://github.com/pdcurtis/cinnamon-applets

 

ScreenshotBattery Applet with Monitoring and Shutdown

Screenshot

This is a simple applet I have written for my laptop because I have recently had a couple of times where I have missed the notifications about low battery. The latest version of Cinnamon also seems to have lost the setting to specify the action when the battery is critical. In any case there is no easy way to set the 'shutdown' level in Mint 18 Sarah/Cinnamon 3.0 . The applet draws on my code for the NUMA (Network Utilisation Monitoring and Alert) Applet so much of the code is well developed and tested.

This applet allows one to set a level at which the machine starts to shutdown (suspend to memory as currently set up) with plenty of warning - the shutdown level is 2/3 of the initial alert level.

The applet normally shows the percentage charge on a coloured background which is:

Green when above the alert level (set currently to 1.5 times the 'shutdown' level.)
Orange between the warning and shutdown level
Red and flashing at and below the Shutdown level (even when charging).

When the battery is Discharging the warning and shutdown regions have a much larger flashing orange or red message in the applet which is difficult to miss.

When the Alert level is reached a modal alert is put up which can not be missed as no input can be made until it is cleared.
When the shutdown level is reached a normal alert box is put up with options of an immediate suspend or cancel - if nothing is done it suspends 30 seconds latter. If cancelled (or the machine is turned back on without the battery being on charge) the alert and shutdown sequence is restarted after the battery has dropped another 1%.

The alert level can be set to between 10% and 40% of full by a slider on the left click menu or in the configuration screen. The refresh rate can also be set in the configuration screen.

The intention is to allow the possibility of leaving suspend with enough battery to close programs and shut down after powering up from suspend without a charger after an accidental unattended suspend. It is suggested that the 'shutdown level' is set to about 10% to allow time. Do not forget that the battery still drains although slowly during suspend.

The right click menu gives access to some useful utilities as well as the change log and this help file.

Many laptops do not implement a suspend well. The suspend which is in use is a Suspend to Memory which is better supported than Hibernate (suspend to disk) but it does use power a little power when in that mode so it is still possible to loose work if the level is set too low or it is left too long. It is sensible to make sure the laptop does suspend reliably before trusting too this applet to save work. The code for suspending is different in Mint 18 to earlier versions. The script calls both methods which should not cause problems but you can comment out the redundant one if you want in suspendScript.

The Applet is designed to work with Mint 17 and higher and Cinnamon 2.0 and higher but currently most of the testing has been with Mint 18. It is currently offered at a beta (development) level. Feedback is welcome.

Requirements:

Cinnamon Version 1.8 or higher as it make comprehensive use of the new Cinnamon Settings Interface for Applets and Desklets.

For full facilities including notifications and audible alerts the zenity sox and libsox-fmt-mp3 libraries must be installed. They can be installed with the terminal command:

sudo apt-get install zenity sox libsox-fmt-mp3

or by the Synaptic Package Manager.

Manual Installation:

Download
Unzip and extract folder batterymonitor@pdcurtis to ~/.local/share/cinnamon/applets/
Install any additional programs required.
Enable the applet in Cinnamon Settings -> Applets
You can also access the Settings Screen from Cinnamon Settings -> Applets

Techniques and Tools used in Applet Development

This is the start of an explanation of some of the techniques used in NUMA and more generally.

Tools:

Validation of the settings- schema.json files

There is an online validator at http://www.jsonlint.com/

Beautification of javascript files

It is important that the layout has correct indentation etc if the code is to be easily understood. There is and online beautification tool which I have used at http://www.jsbeautifier.org/

Comparison of Files

Most of you will be aware of programs such as diff but Meld has an excellent graphical interface and allows one to merge and edit files in a GUI interface is ideal when debugging code including applets. It is in the normal Repositories but needs to be installed.

Git

Git is a distributed revision control and source code management. Git was initially designed and developed by Linus Torvalds for Linux kernel development in 2005. It is ideal for applet development but has a big learning curve. I believe it should be a positive recomendation for any applets which are made available to others to use on the cinnamon spices web site should use Git.

My applets can all be found at https://github.com/pdcurtis/cinnamon-applets . The latest commits on github will be development versions and may not be suitable for your use - read the change logs very carefully. Some of the development versions which have been uploaded to this page and all the release versions uploaded to Cinnamon-Spices will have Tags.

I have written An Introduction to Git - Applications in Cinnamon Applet Development which includes a basic guide on how to install and use Git to access my git repository and obtain the latest versions as well as previous versions and continues to how you can set up your own repositories and use GitHub.

Getting out of trouble using Git

I unfortunately managed to have an Applet which broke Cinnamon preventing any display on my laptop whilst I was away from home. I however found I could do a remote login via SSH to my user giving me terminal access from my phone as the Wifi connection was set up and working. I had Git set up so once I was logged in I could run Git and commit the files in the faulty version so I could see latter what I had done wrong and then checkout the working master branch and login again using Cinnamon. Two commands and I was back in business. Without the possibility of a remote log in or another user set up on the machine I would have had to have used a LiveUSB and deleted or moved elsewhere the faulty applet.

The applet problem turned out to be a faulty edit of the settings-schema.json file where a number intended to be 200000 had lost the initial 2 giving an upper limit of zero. I would have expected that sort of error to be trapped in the Cinnamon Settings software - I will be be careful in future. Since then I have had another series of lockouts after editing a settings-schema.jason file and had to use a remote logins over SSH again. In the second case I only cleared it by deleting a widget completely and re-entering it.

I have covered how to login from a different user/machine in my Development Diary part 27

Documentation

There seems to be very little documentation to do with writing applets but the following links are a useful start:

Some basics about Applets.

Applets are to a large extent event drive so most will do nothing after being initiated until an event takes place and this can make the flow difficult to follow as some functions may not have an obvious call in the applet code. Examples are:

Snippets of JavaScript for Applets

I am initially going to take up where the Settings Applet Tutorial stopped and look at adding 'active' left and right click menu items.

Add a left click menu

Although this is covered in the tutorial pretty well I will include some code here for completeness. The code lives in the _init section right at the top of an applet

// Set up left click menu
this.menuManager = new PopupMenu.PopupMenuManager(this);
this.menu = new Applet.AppletPopupMenu(this, orientation);
this.menuManager.addMenu(this.menu);

Right Click (Context) menu

You do not need to add one of these as it is already created for you and called _applet_context_menu and is ready to use. In cinnamon 2.0 there are two initial entries to Configure the applet and Remove the applet - Beware, these initial entries are also cleared by:

this._applet_context_menu.removeAll();

I have found it may take two calls to remove them and the presence of the Configure item means applets may need to be different between versions for 1.8 and 2.0. I have recently found there is access to the version number through an environment variable. A code snipet follows to show how it can be used.

Checking version cinnamon version to avoid two Configure... entries and to use the correct text editor

// Add a context menu call to cinnamon-settings if version less than 2.0
if (this.versionCompare( GLib.getenv('CINNAMON_VERSION') ,"2.0" ) < 0 ){
this._applet_context_menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
let menuitem = new PopupMenu.PopupMenuItem("Configure..");
menuitem.connect('activate', Lang.bind(this, function (event) {
GLib.spawn_command_line_async('cinnamon-settings applets ' + this.UUID);
}));
this._applet_context_menu.addMenuItem(menuitem);
}

// Choose Text Editor depending on whether Mint 18 with Cinnamon 3.0 and latter
if (this.versionCompare( GLib.getenv('CINNAMON_VERSION') ,"3.0" ) <= 0 ){
this.textEd = "gedit";
} else {
this.textEd = "xed";
}

// Function to Compare two version numbers (strings) based on code by Alexey Bass (albass)
// Takes account of many variations of version numers including cinnamon.
versconCompare: function (left, right) {
if (typeof left + typeof right != 'stringstring')
return false;
var a = left.split('.'),
b = right.split('.'),
i = 0, len = Math.max(a.length, b.length);
for (; i < len; i++) {
if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
return 1;
} else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
return -1;
}
}
return 0;
},

Active (Clickable) Text menu items including rewriting the displayed text

There seem to be many ways to do this and the way chosen here is what I have been using for the NUMA applet and has the advantage that the contents of the menu can, to some extent, be updated without the whole menu having to be rebuilt from scratch which is a slow operation.

// This assumes you have already added a menu called menu
this.menuitem1 = new PopupMenu.PopupMenuItem("Initial Text String to display");
this.menuitem1.connect('activate', Lang.bind(this, function () {
    // Code to execute when clicked here
    // .........
}));
this.menu.addMenuItem(menuitem1);

Once one has added menuitem1 it is possible to overwrite the text string with updated information. I do this in several places in NUMA to reflect changes when a setting has been updated and to show the latest values of upload and download rates. Because we are using this.menuitem1 we can update it from anywhere in the applet.

this.menuitem1.label.text = "New information string to display";

There is also a shorter and neater way to add an action but it does not allow you to rewrite the text string:

this.menu.addAction("Fixed text string to display", function(event){
    // Add actions to take here ;
    // .......
});

If we want a non-reactive entry in the menu , for example a heading, we can add

this.menuitemStatic1 = new PopupMenu.PopupMenuItem("Informative text string - not clickable", {
    reactive: false
});
this.menu.addMenuItem(this.menuitemStatic1);

Creating a sub menu

We can create another level of menu items with a sub-menu like this:

this.subMenu1 = new PopupMenu.PopupSubMenuMenuItem("Name of second level menu ");
this.menu.addMenuItem(this.subMenu1);

Adding Items to this menu is exactly the same as to a normal top level menu except that one puts this.subMenu1.menu... instead of this.menu..... so we add the first submenu item by:

this.subMenuItemStatic1 = new PopupMenu.PopupMenuItem("Informative text string in submenu - not clickable", {
reactive: false
});
this.subMenu1.menu.addMenuItem(this.subMenuItemStatic1);

Right Click 'Context' Submenus

These can be added in a similar way to those for a left click menu but using _applet_context_menu when adding the submenu. You however do not use _applet_sub_menu when adding the items - I do not understand but the following works! Note the red bits.

this.subMenu1 = new PopupMenu.PopupSubMenuMenuItem("Name of second level menu ");
this._applet_context_menu.addMenuItem(this.subMenu1);

this.menuitemStatic1 = new PopupMenu.PopupMenuItem("Informative text string - not clickable", {
reactive: false
});
this.subMenu1.menu.addMenuItem(this.menuitemStatic1);

Adding a Separator

This is very easy for a left click menu:

this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());

or for a right click 'context' menu

this._applet_context_menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());

Activating the left and right click menus.

We now need to have the code to Open the menu when the applet is clicked. The right click 'Context' menu opens automatically on a right click but the let click menu needs to have an on_applet_clicked function as below:

on_applet_clicked: function(event) {
if (!this.menu.isOpen) {
this._update();
}
this.menu.toggle();
},

Running an update loop

// This is the loop run at refreshInterval rate to call updateUI() to update the display in the applet and tooltip

 updateLoop: function () {
   this.updateUI();
   // Also inhibit when applet after has been removed from panel
   if (this.applet_running == true) {
       Mainloop.timeout_add_seconds(this.refreshInterval, Lang.bind(this, this.updateLoop));
   }
},

Finishing off the applet code

The following is the standard code at the end of the applet. It must close MyApplet.prototype = {..... in all cases and there must be the creation of an instance of MyApplet.

In addition one really needs to clear down (finalize) all the linkages created with the settings panel through the .json file if and only if one is using the feature.

// This is the code at the end of the applet

     on_applet_removed_from_panel: function () {
        // Addition when update timer loops need to be stopped
        this.applet_running = false;

        this.settings.finalize();
     }

};       // This is the termination of the MyApplet.prototype = {

function main(metadata, orientation, panel_height, instance_id) {
let myApplet = new MyApplet(metadata, orientation, panel_height, instance_id);
return myApplet;
}

Terminating Loops after removal from panel

It has recently been found that applets using timer loops based on Mainloop timers can still have the loops running even after they have been removed from the panel and additional code is needed in the on_applet_removed_from_panel function to terminate such loops. A suggested mechanism is to have an applet_running flag which is set during initialisation of the applet and cleared on exit in the on_applet_removed_from_panel function which is always tested before restarting the Mainloop. This has been added to the two blocks of code above

Making the Applet independent of its location (UUID)

Most Applets which use settings have the UUID (folder name in which the applet lives) hard coded in. It is possible to get this from the metadata which has at least two vales which are useful path and uuid. The path is of value in, for example, opening a configuration or help file or opening the Settings screen. I will use the Settings screen as an examples it needs the UUID and opening a changelog file which is in the applet folder..

// Following are in _init
this.UUID = metadata.uuid;
this.changelog = metadata.path + "/changelog.txt";

// Following are in a menu
let menuitem = new PopupMenu.PopupMenuItem("Settings");
menuitem.connect('activate', Lang.bind(this, function (event) {
GLib.spawn_command_line_async('cinnamon-settings applets ' + this.UUID);
}));
this._applet_context_menu.addMenuItem(menuitem);

this.menuItem1 = new PopupMenu.PopupMenuItem("View the Changelog");
this.menuItem1.connect('activate', Lang.bind(this, function (event) {
GLib.spawn_command_line_async('gedit ' + this.changelog );
}));
this.menu.addMenuItem(this.menuItem1);

Using of Cascading Style Sheets from JavaScript in Cinnamon Applets

So far I have found the following ways of applying styles to objects.

Firstly when creating new instances of objects (actors), for example:

this.actor = new St.BoxLayout({
name: 'windowList',
style_class: 'window-list-box'
});

let label = new St.Label({
text: value ,
style_class: 'centered'
});

Secondly styles can be added and removed from existing objects - one can check if a style is in use before removing it and adding a new style. Note: An existing style-classe needs to be removed before adding a new one.

this.actor.add_style_class_name('style-name');

if (this.actor.has_style_class_name('style-name')) {
this.actor.remove_style_class_name('style-name');
}
this.actor.add_style_class_name('new-style-name');
this.actor.set_style('margin-bottom: 0px;');
this.actor.set_style('padding-bottom: 0px;');

There may be a way to find out the current style_class which has been applied but I have not yet found it!

Finally one can work with pseudo styles (hover, active, focus etc) by:

actor.remove_style_pseudo_class('focus');
actor.add_style_pseudo_class('focus');

 

Localisation - how to add l10n/translation support to an applet.

l10n is a a numeronym - a number-based word used as an abreviation it means there are 10 letters between the l and n at the begining and end of localisation.

A good start is to look at the [Tutorial] How to add l10n/translation support to an applet by @NikoKrause including the comments which follow.

Note the const UUID has to be changed in my applets as I already use this.UUID which I derive from metadata.uuid so my standard insert is:

const GLib = imports.gi.GLib; // ++ Needed for starting programs as well as l10n support so already present.

// l10n/translation support as per NikoKrause tutorial modified as UUID already used!
const Gettext = imports.gettext
const UUIDl10n = "bumblebee@pdcurtis"
Gettext.bindtextdomain(UUIDl10n, GLib.get_home_dir() + "/.local/share/locale")

function _(str) {
  return Gettext.dgettext(UUIDl10n, str);
}

I have now started to use a better version.

// ++ Needed for translations,lives with other const at top
const Gettext = imports.gettext;

// ++ Always needed if you want localisation/translation support
// New l10n support thanks to ideas from @Odyseus, @lestcape and @NikoKrause

var UUID;
function _(str) {
     let customTrans = Gettext.dgettext(UUID, str);
     if (customTrans !== str && customTrans !== "")
        return customTrans;
    return Gettext.gettext(str);
}

// ++ Part of new l10n support
// lives in _init in section "Make Metadata values available within applet ...."

        UUID = metadata.uuid;
        Gettext.bindtextdomain(metadata.uuid, GLib.get_home_dir() + "/.local/share/locale");

Preparing applet.js translatable strings

Every String you want to be translated, needs to be put in brackets with underscore _(), for example

_("This is a text, which needs to be translated")

Create translation template for the first time or updating it

The command creates a translation template file yourApplet.pot in the po folder.

If you need to update it you can make the call another time and it will overwrite the existing file.

Vertical Panels

Vertical panels were added in Cinnamon 3.2 (issued with Mint 18.1). Suitable applets can be added to a vertical panel or dragged between horizontal and vertical panels.Not all applets are suitable for vertical panels and they are inhibited by default in many cases. There is no separate documentaion that I have found - all the information required is however present in the initial comment in the conversation associated with the Pull Request on Github where it was added to Cinnamon 3.2 at https://github.com/linuxmint/Cinnamon/pull/4996

I have extracted some of the important points which affect applet design.

Implementing Applets for Vertical Panel

Taken from https://github.com/linuxmint/Cinnamon/pull/4996

Applets for placing in a vertical panel have to fit. In practice that means there is space for an icon, nothing else. Placing larger applets in a vertical panel disturbs the alignment of all other applets in that part of the panel, and it all will look very broken, so protection has been added to guard against that.

Applets based around IconApplet are assumed to be suitable for vertical panels and can be placed there. However if you maintain one of these then please do check they work OK - your applet may write additional information out to the screen that Cinnamon does not know about when the applet is loaded. This will mess up the central alignment unless suppressed.

All other applets need an explicit declaration in their code that they work in a vertical panel. If this is not done then a user will simply not be able to place them there from the applet manager, or by drag and drop in panel edit mode, and they will be turned off if moving a whole panel from a horizontal to a vertical position.

The mechanism for doing this is very simple, just place a call in your code:

this.setAllowedLayout(Applet.AllowedLayout.BOTH);

Any sophisticated applet may well need logic that has different actions dependent on the type of panel it is in, so would need a call coded like this:

on_orientation_changed: function (orientation) {
  this.orientation = orientation;

  if (this.orientation == St.Side.LEFT || this.orientation == St.Side.RIGHT) { // vertical
    ...
  } else { // horizontal
    ...
  }
  ...
}

If you have an applet with a label that needs suppressing in a vertical panel, you will need code that explicitly shows or hides the label like this:

on_orientation_changed: function(orientation) {
  if (orientation == St.Side.LEFT || orientation == St.Side.RIGHT)
    this.hide_applet_label(true);
  else
    this.hide_applet_label(false);
},

If you have long multi-element applets like the window list, the panel launcher, the workspace switcher or the systray then it is likely you will have to intermediate a management container that can facilitate switching between horizontal and vertical modes. Take a look at the code in these standard applets as a start (github: Cinnamon/files/usr/share/cinnamon/applets) If you have an applet that changes its dimension then take a look at the spacer applet code for a starting point.

Where different CSS is needed for vertical and horizontal presentations then this has been done by including .vertical additional CSS. Again, take a look at the panel launcher or window list standard applets for how to use this - add 'vertical' style in a vertical panel, take it off again in a horizontal panel.

One last thing is to ensure that your code uses the current parameters and calls to init(). If your code does not include the panel height and orientation parameters and use them in an init call then it is likely your applet will a) come up the wrong size when added until the next Cinnamon restart b) orient off-centre in a vertical panel, until the next Cinnamon restart c) have sub-standard popup menu alignment . Take a look at the stock applets in github: Cinnamon/files/usr/share/cinnamon/applets if in doubt.

MyApplet.prototype = {
  __proto__: Applet.IconApplet.prototype,

  _init: function(metadata, orientation, panel_height, instance_id) {
    Applet.IconApplet.prototype._init.call(this, orientation, panel_height, instance_id);

Taken from https://github.com/linuxmint/Cinnamon/pull/4996

Modification and Design of Applets for vertical panels

I have converted two of my applets to use vertical panels, the others depend on presenting text information such as temperature, time or data flows.

The two I have converted now use TextIconApplet instead of TextIcon and display the primary information through choice of icon to show the status and hide the associated text in a vertical panel and depend on the user accessing the menu or label for additional information.

There are functions to turn icons and text on and off fully in a vertical panel. The usual way in a horizontal panel is just to use a null string but in a vertical panel you get an empty 'box' under the icon.

The first problem to be overcome is that vertical panels only exist in Cinnamon 3.2 and higher and the call (this.setAllowedLayout(Applet.AllowedLayout.BOTH)) to allow use of a vertical panel is only available in 3.2 and higher. If it is called in earlier versions it causes an error which prevents the applet running - I have checked this is the case in Mint 17.3 with Cinnamon 2.8. The on_orientation_changed function and check within it - if (this.orientation == St.Side.LEFT || this.orientation == St.Side.RIGHT) should be OK back to Cinnamon 2.2 or earlier but I have only checked as far as 2.8.

In extending my applets for vertical panels I have had to include a version check before any calls to functions which may only be present in Cinnamon version 3.2 and higher.

So in _init I have:

          if (this.versionCompare( GLib.getenv('CINNAMON_VERSION') ,"3.2" ) >= 0 ){
               this.setAllowedLayout(Applet.AllowedLayout.BOTH);
          }

          ......

          this.on_orientation_changed(orientation); // Initialise for panel orientation

and my on_orientation_changed function is:

on_orientation_changed: function (orientation) {
     this.orientation = orientation;
     if (this.versionCompare( GLib.getenv('CINNAMON_VERSION') ,"3.2" ) >= 0 ){
          if (this.orientation == St.Side.LEFT || this.orientation == St.Side.RIGHT) {
               // vertical
               this.isHorizontal = false;
          } else {
               // horizontal
               this.isHorizontal = true;
           }
      } else {
            this.isHorizontal = true; // Do not check unless >= 3.2 and force true.
      }
},

The this.isHorizontal flag is forced to be true for Cinnamon versions lower than 3.2 and you should ensure that all calls which may be suspect in earlier versions do not take place unless this.isHorizontal is false. The logic could obviously be tightened but I have left it like this to give more flexability for extension.

I have no evidence of problems but I have avoided the following in pre 3.2 versions by appropriate use of the flag:

this.hide_applet_label(true);
this.hide_applet_label(false);
hide_applet_icon();

Note that hide_applet_icon() does not seem to have a true/false parameter

Linking README.md and CHANGELOG.md files

The cinnamon-spices-applets repository has each applet in a separate folder which is the UUID. This contains two files, README.md and CHANGELOG.md which are displayed as part of the spices web site. In my case I used to have files help.txt and changelog.txt which were similar in the applet folder which could also be displayed using a housekeeping sub-menu item on the context (right click) menu. The overall folder structure is cinnamon-spices-applets/UUID/files/UUID where UUID is of the form bumlebee@pdcurtis and the lower level (UUID/files/UUID) folder is the one that is 'installed' into ~/.local/share/cinnamon/applets on your machine.

I have done some tests and the spices web site does resolve symbolic links so it is possible to use a symbolic link to avoid duplicating the files. So one changes into the UUID folder and creates the symbolic links by:

cd ~/cinnamon-spices-applets/bumblebee@pdcurtis
ln -s files/bumblebee@pdcurtis/README.md
ln -s files/bumblebee@pdcurtis/CHANGELOG.md

You obviously need to delete any existing files before linking to the applet folder

Checking if Dependencies are loaded.

It has been decided it's easier for the applet to check its own dependencies than try to come up with some reliable way for the applet/extension system to do this and show a notification.

The most common test is:

if (!GLib.find_program_in_path("package-name")) { }

A good example can be seen from @mtwebster in his CPU frequency applet: http://cinnamon-spices.linuxmint.com/applets/view/70 or in my bumblebee applet below:

const Main = imports.ui.main; // Needed for criticalNotify() may be present if not add.

// Check that Bumblebee is installed by presence of optirun
if (!GLib.find_program_in_path("optirun")) {
let icon = new St.Icon({ icon_name: 'error',
icon_type: St.IconType.FULLCOLOR,
icon_size: 36 });
Main.criticalNotify("Bumblebee program not installed", "You appear to be missing some of the required programs for 'bumblebee' to switch graphics processors using NVIDIA Optimus.\n\nPlease read the help file.", icon);
this.bumblebeeMissing = true;
} else {
this.bumblebeeMissing = false;
}

Warning about LMDE and GLib.find_program_in_path()

The initial version which checked for bumblebeed did not work under LMDE because in LMDE, bumblebeed is installed to /usr/sbin, but the applet is using path of the logged in user when searching for it (which does not contain /sbin or /usr/sbin). optirun is however installed in /usr/bin which is in the paths searched. You can check the path by

echo $PATH

Alternate 1 - use of GLib.file_test()

@mtwebster commented For executables, g_find_program_in_path is best - as mentioned the app sys works from our menu tree, which is populated solely via desktop files.

For normal files, I'd use g_file_test - don't use g_file_query_exists (it blocks). Using g_file_query_info, you can construct an asynchronous version of checking whether a file exists, but I'm not sure it's worth it here, g_file_test should do the trick. It does make me wonder if we would benefit from a nice rolled-up function that any applet could use - an asynchronous file existence check.

One can use GLib.file_test() in the following way:

this._isFileInstalled = GLib.file_test('file', GLib.FileTest.EXISTS);

and it is used that way in a number of applets. I had not previously though about the issue of synchronous and asynchronous.

More information on GLib.file_test()

Alternate 2 - Use of try and catch error checking

Neither of the methods above enable one to see if a library such as GTop is installed. One can however use a try {} and catch(e) {} to catch the error and issue a warning and set a flag to inhibit calls involving the library. An example follows:

// Check that GTOP library is installed as applet will not run without it
// Based on method used in applet hwmonitor@sylfurd
// All functions wusing GTop have an if (!GTopInstalled) {return}; added at start
let GTopInstalled = true;
try {
   var GTop = imports.gi.GTop;
} catch(e){
   let icon = new St.Icon({ icon_name: 'error',
   icon_type: St.IconType.FULLCOLOR,
   icon_size: 36 });
   Main.criticalNotify(_("Some Dependencies not Installed"), _("You appear to be missing some of the programs or libraries required for this applet to run.\n\nPlease read the help file on how to install them."), icon);
   GTopInstalled = false;
}
.......
MyApplet.prototype = {
   __proto__: Applet.Applet.prototype,
   _init: function (metadata, orientation, panel_height, instance_id) {
   Applet.Applet.prototype._init.call(this, orientation, panel_height, instance_id);
   if (!GTopInstalled) {return};
   ......

Warning - You need to position the localisation support earlier than the check

Find text string in all files in current folder and subfolders.

This is very useful to search for use of programs etc when using Git

grep -rl "searchstring" .
where

Note the . (dot) at the end which could also be any /path

More interesting options at https://askubuntu.com/questions/55325/how-to-use-grep-command-to-find-text-including-subdirectories

Issues resulting from changes between Cinnamon Versions

Checking compliance with mozjs38

Ubuntu/Mint/Cinnamon uses the Monzilla Spidermonkey JavaScript engine which has been updated from version 24 to 38 . The new version has more demanding error checking and, in particular, it no longer tolerates multiple let declarations.

There is a script to allow checking which is in ~/Cinnamon/utils/check-js. I have found that the easiest way to run it is to copy it into one's applet folder and run by

./check-js

Changes required to Applets and Desklets under Cinnamon 4.0

Mint 19.1 which has Cinnamon 4.0 no longer supports the old network manager and loading applets or desklets which link to the old non-existent libraries causes a segfault even when wrapped in the try-catch already used in my applets to support both types of network manager and hence a number of different distributions.

To aid testing a requirement and test was been put in place to check that problem xlets have been modified by checking they use use multiversion and have a 4.0 folder. So my some of my applets require multiversion to be defined and possibly cinnamon-version used in metadata.json. This has led to a search for information as the Cinnamon and xlet documentation is not always very up-to-date even when it can be found!

Cinnamon Extension Versioning

The only actual documentation I could find about where versions should live was at http://developer.linuxmint.com/reference/git/cinnamon-tutorials/xlet-versioning.html. To quote:

To enable extension versioning,

Extensions have to add the line

{
"multiversion": true
}

in metadata.json. The different versions should be put in different subdirectories. For example, the version for 2.6 should be put in extension@uuid/2.6/. The contents in 2.6/ should be exactly what you will normally put in extension@uuid/, apart from metadata.json, which should always be put in the parent directory, ie. extension@uuid/.

You do not need to create a subdirectory for every single Cinnamon version out there. Cinnamon looks for the most recent subdirectory that is not newer than the running Cinnamon version. For example, if you are running 2.6 and there are 2.4, 2.8 directories, the 2.4 directory will be loaded, until the you upgrade to 2.8 in which case the 2.8 directory will be used. Minor version numbers can also be used, eg. 2.6.4, and are sorted accordingly.

If no suitable directory is found, then the contents in extension@uuid/ will be loaded. Note that Cinnamon versions prior to 2.6 will not understand this directory magic, and will always try to load the contents in extension@uuid/. Hence it is suggested that extension maintainers put the version for 2.4 in extension@uuid, and create new directories if changes specific to newer Cinnamon versions are made. Don't make a new directory whenever a Cinnamon version is out since it is just a waste of space (and maintenance effort).

Extracted from http://developer.linuxmint.com/reference/git/cinnamon-tutorials/xlet-versioning.html

Cinnamon has another mechanism for version control handling which is also added to metadata.json in the form

{
"cinnamon-version": ["2.2","2.4","2.6","2.8","3.0","3.2","3.4","3.6","3.8","4.0"]
}

Only versions which match entries are loaded.

so a typical metadata.json file might look like this:

{
   "max-instances": "1",
   "uuid": "netusagemonitor@pdcurtis",
   "name": "Network Data Usage Monitor",
   "description": "A Comprehensive Data Usage Monitor with alerts and cumulative data functions",
   "version": "3.2.6",
   "multiversion": true,
   "cinnamon-version": ["2.2","2.4","2.6","2.8","3.0","3.2","3.4","3.6","3.8","4.0"]
}

I have noticed in https://github.com/linuxmint/Cinnamon/wiki/%5Bdevelopment%5D-extensions that metadata.json has:

requiredProperties: ['uuid', 'name', 'description', 'cinnamon-version'],
niceToHaveProperties: ['url'],

If this was the case as it means every applet would need cinnamon-version which would have to be updated every time the cinnamon version is changed which is lot of extra PRs!

I have now looked at all the applets which either use cinnamon-version (13) or multiversion (14) and they mostly overlap and I have assumed most of them work although I have put emphasis on those from those from authors I know about. As a first check I did searches with grep from my applet folder to see how many current applets have a line with 'cinnamon-version' :

peter@defiant:~/cinnamon-spices-applets$grep -Rw . -e 'cinnamon-version'

which showed there were only 13 of 148 applets which use 'cinnamon-version' in metadata.json and quite a few already had"4.0" included. So it as clear that a 'cinnamon-version' is not currently obligatory. There are also several which do not get to "3.8" and can no longer be loaded. The options are R for recursive and w whole word - you can add n which will also give the line number in the file. This is a very useful and powerful search without having to remember complex commands and I found the number of applets using multiversion (14) in same way.

I also run tests:

Some conclusions are:

So I have:


Before You Leave

I would be very pleased if visitors could spare a little time to give me some feedback - it is the only way I know who has visited, if it is useful and how I should develop it's content and the techniques used. I would be delighted if you could send comments or just let me know you have visited by sending a quick Message to me.

Link to W3C HTML5 Validator Copyright © Peter & Pauline Curtis
Fonts revised: 28th April, 2021