Guest User

Hack for make the power cinnamon applet work on Ubuntu 16.04

a guest
May 6th, 2017
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const Applet = imports.ui.applet;
  2. const Clutter = imports.gi.Clutter;
  3. const Gio = imports.gi.Gio;
  4. const Interfaces = imports.misc.interfaces
  5. const Lang = imports.lang;
  6. const St = imports.gi.St;
  7. const Tooltips = imports.ui.tooltips;
  8. const PopupMenu = imports.ui.popupMenu;
  9. const Pango = imports.gi.Pango;
  10. const Main = imports.ui.main;
  11. const Settings = imports.ui.settings;
  12. const GnomeSession = imports.misc.gnomeSession;
  13. const Mainloop = imports.mainloop;
  14.  
  15. const BrightnessBusName = "org.cinnamon.SettingsDaemon.Power.Screen";
  16. const KeyboardBusName = "org.cinnamon.SettingsDaemon.Power.Keyboard";
  17.  
  18. const UPDeviceType = {
  19.     UNKNOWN: 0,
  20.     AC_POWER: 1,
  21.     BATTERY: 2,
  22.     UPS: 3,
  23.     MONITOR: 4,
  24.     MOUSE: 5,
  25.     KEYBOARD: 6,
  26.     PDA: 7,
  27.     PHONE: 8,
  28.     MEDIA_PLAYER: 9,
  29.     TABLET: 10,
  30.     COMPUTER: 11
  31. };
  32.  
  33. const UPDeviceState = {
  34.     UNKNOWN: 0,
  35.     CHARGING: 1,
  36.     DISCHARGING: 2,
  37.     EMPTY: 3,
  38.     FULLY_CHARGED: 4,
  39.     PENDING_CHARGE: 5,
  40.     PENDING_DISCHARGE: 6
  41. };
  42.  
  43. function deviceTypeToString(type) {
  44.     switch (type) {
  45.         case UPDeviceType.AC_POWER:
  46.             return _("AC adapter");
  47.         case UPDeviceType.BATTERY:
  48.             return _("Laptop battery");
  49.         case UPDeviceType.UPS:
  50.             return _("UPS");
  51.         case UPDeviceType.MONITOR:
  52.             return _("Monitor");
  53.         case UPDeviceType.MOUSE:
  54.             return _("Mouse");
  55.         case UPDeviceType.KEYBOARD:
  56.             return _("Keyboard");
  57.         case UPDeviceType.PDA:
  58.             return _("PDA");
  59.         case UPDeviceType.PHONE:
  60.             return _("Cell phone");
  61.         case UPDeviceType.MEDIA_PLAYER:
  62.             return _("Media player");
  63.         case UPDeviceType.TABLET:
  64.             return _("Tablet");
  65.         case UPDeviceType.COMPUTER:
  66.             return _("Computer");
  67.         default:
  68.             return _("Unknown");
  69.     }
  70. }
  71.  
  72. function deviceToIcon(type, icon) {
  73.     switch (type) {
  74.         case UPDeviceType.MONITOR:
  75.             return ("video-display");
  76.         case UPDeviceType.MOUSE:
  77.             return ("input-mouse");
  78.         case UPDeviceType.KEYBOARD:
  79.             return ("input-keyboard");
  80.         case UPDeviceType.PHONE:
  81.         case UPDeviceType.MEDIA_PLAYER:
  82.             return ("phone-apple-iphone");
  83.         case UPDeviceType.TABLET:
  84.             return ("input-tablet");
  85.         case UPDeviceType.COMPUTER:
  86.             return ("computer");
  87.         default:
  88.             if (icon) {
  89.                 return icon;
  90.             }
  91.             else {
  92.                 return ("battery-full");
  93.             }
  94.     }
  95. }
  96.  
  97. function DeviceItem() {
  98.     this._init.apply(this, arguments);
  99. }
  100.  
  101. DeviceItem.prototype = {
  102.     __proto__: PopupMenu.PopupBaseMenuItem.prototype,
  103.  
  104.     _init: function(device, status) {
  105.         PopupMenu.PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
  106.  
  107.         let [device_id, vendor, model, device_type, icon, percentage, state, time, timepercentage] = device;
  108.  
  109.         this._box = new St.BoxLayout({ style_class: 'popup-device-menu-item' });
  110.         this._vbox = new St.BoxLayout({ style_class: 'popup-device-menu-item', vertical: true});
  111.  
  112.         let description = deviceTypeToString(device_type);
  113.         if (vendor != "" || model != "") {
  114.             description = "%s %s".format(vendor, model);
  115.         }
  116.  
  117.         this.label = new St.Label({ text: "%s %d%%".format(description, Math.round(percentage)) });
  118.         let statusLabel = new St.Label({ text: "%s".format(status), style_class: 'popup-inactive-menu-item' });
  119.  
  120.         let device_icon = deviceToIcon(device_type, icon);
  121.         if (device_icon == icon) {
  122.             this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon), icon_type: St.IconType.SYMBOLIC, style_class: 'popup-menu-icon' });
  123.         }
  124.         else {
  125.             this._icon = new St.Icon({icon_name: device_icon, icon_type: St.IconType.SYMBOLIC, icon_size: 16});
  126.         }
  127.  
  128.         this._box.add_actor(this._icon);
  129.         this._box.add_actor(this.label);
  130.  
  131.         this._vbox.add_actor(this._box);
  132.         this._vbox.add_actor(statusLabel);
  133.  
  134.         this.addActor(this._vbox);
  135.  
  136.     }
  137. }
  138.  
  139. function BrightnessSlider(applet, label, icon, busName, minimum_value){
  140.     this._init(applet, label, icon, busName, minimum_value);
  141. }
  142.  
  143. BrightnessSlider.prototype = {
  144.     __proto__: PopupMenu.PopupSliderMenuItem.prototype,
  145.  
  146.     _init: function(applet, label, icon, busName, minimum_value){
  147.         PopupMenu.PopupSliderMenuItem.prototype._init.call(this, 0);
  148.         this.actor.hide();
  149.  
  150.         this._applet = applet;
  151.         this._seeking = false;
  152.         this._minimum_value = minimum_value;
  153.  
  154.         this.connect("drag-begin", Lang.bind(this, function(){
  155.             this._seeking = true;
  156.         }));
  157.         this.connect("drag-end", Lang.bind(this, function(){
  158.             this._seeking = false;
  159.         }));
  160.  
  161.         this.icon = new St.Icon({icon_name: icon, icon_type: St.IconType.SYMBOLIC, icon_size: 16});
  162.         this.removeActor(this._slider);
  163.         this.addActor(this.icon, {span: 0});
  164.         this.addActor(this._slider, {span: -1, expand: true});
  165.  
  166.         this.label = label;
  167.         this.toolTipText = label;
  168.         this.tooltip = new Tooltips.Tooltip(this.actor, this.tooltipText);
  169.  
  170.         Interfaces.getDBusProxyAsync(busName, Lang.bind(this, function(proxy, error) {
  171.             this._proxy = proxy;
  172.             this._proxy.GetPercentageRemote(Lang.bind(this, this._dbusAcquired));
  173.         }));
  174.     },
  175.  
  176.     _dbusAcquired: function(b, error){
  177.         if(error)
  178.             return;
  179.  
  180.         this._updateBrightnessLabel(b);
  181.         this.setValue(b / 100);
  182.         this.connect("value-changed", Lang.bind(this, this._sliderChanged));
  183.  
  184.         this.actor.show();
  185.  
  186.         //get notified
  187.         this._proxy.connectSignal('Changed', Lang.bind(this, this._getBrightness));
  188.         this._applet.menu.connect("open-state-changed", Lang.bind(this, this._getBrightnessForcedUpdate));
  189.     },
  190.  
  191.     _sliderChanged: function(slider, value) {
  192.         if (value < this._minimum_value) {
  193.             value = this._minimum_value;
  194.         }
  195.         this._setBrightness(Math.round(value * 100));
  196.     },
  197.  
  198.     _getBrightness: function() {
  199.         //This func is called when dbus signal is received.
  200.         //Only update items value when slider is not used
  201.         if (!this._seeking)
  202.             this._getBrightnessForcedUpdate();
  203.     },
  204.  
  205.     _getBrightnessForcedUpdate: function() {
  206.         this._proxy.GetPercentageRemote(Lang.bind(this, function(b) {
  207.             this._updateBrightnessLabel(b);
  208.             this.setValue(b / 100);
  209.         }));
  210.     },
  211.  
  212.     _setBrightness: function(value) {
  213.         this._proxy.SetPercentageRemote(value, Lang.bind(this, function(b) {
  214.             this._updateBrightnessLabel(b);
  215.         }));
  216.     },
  217.  
  218.     _updateBrightnessLabel: function(value) {
  219.         this.tooltipText = this.label;
  220.         if(value)
  221.             this.tooltipText += ": " + value + "%";
  222.  
  223.         this.tooltip.set_text(this.tooltipText);
  224.     }
  225. };
  226.  
  227. function MyApplet(metadata, orientation, panel_height, instanceId) {
  228.     this._init(metadata, orientation, panel_height, instanceId);
  229. }
  230.  
  231.  
  232. MyApplet.prototype = {
  233.     __proto__: Applet.TextIconApplet.prototype,
  234.  
  235.     _init: function(metadata, orientation, panel_height, instanceId) {
  236.  
  237.         Applet.TextIconApplet.prototype._init.call(this, orientation, panel_height, instanceId);
  238.  
  239.         this.metadata = metadata;
  240.  
  241.         this.settings = new Settings.AppletSettings(this, metadata.uuid, instanceId);
  242.         this.settings.bindProperty(Settings.BindingDirection.IN, "labelinfo", "labelinfo", Lang.bind(this, this._devicesChanged), null);
  243.  
  244.         Main.systrayManager.registerRole("power", metadata.uuid);
  245.         Main.systrayManager.registerRole("battery", metadata.uuid);
  246.  
  247.         this.menuManager = new PopupMenu.PopupMenuManager(this);
  248.         this.menu = new Applet.AppletPopupMenu(this, orientation);
  249.         this.menuManager.addMenu(this.menu);
  250.  
  251.         this._deviceItems = [ ];
  252.         this._devices = [ ];
  253.         this._primaryDeviceId = null;
  254.         this.panel_icon_name = ''; // remember the panel icon name (so we only set it when it actually changes)
  255.  
  256.         this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
  257.  
  258.         this.brightness = new BrightnessSlider(this, _("Brightness"), "display-brightness", BrightnessBusName, 0.01);
  259.         this.keyboard = new BrightnessSlider(this, _("Keyboard backlight"), "keyboard-brightness", KeyboardBusName, 0);
  260.         this.menu.addMenuItem(this.brightness);
  261.         this.menu.addMenuItem(this.keyboard);
  262.  
  263.         this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
  264.  
  265.         this.menu.addSettingsAction(_("Power Settings"), 'power');
  266.  
  267.         this.actor.connect("scroll-event", Lang.bind(this, this._onScrollEvent));
  268.  
  269.         Interfaces.getDBusProxyAsync("org.cinnamon.SettingsDaemon.Power", Lang.bind(this, function(proxy, error) {
  270.             this._proxy = proxy;
  271.             this._proxy.connect("g-properties-changed", Lang.bind(this, this._devicesChanged));
  272.             this._devicesChanged();
  273.         }));
  274.    
  275.     this._doUpdateUI();
  276.     },
  277.     _doUpdateUI: function(){
  278.     if (this._proxy) {
  279.             this._devicesChanged();
  280.     }
  281.         Mainloop.timeout_add_seconds(90, Lang.bind(this, this._doUpdateUI));
  282.     },
  283.     _onButtonPressEvent: function(actor, event){
  284.         //toggle keyboard brightness on middle click
  285.         if(event.get_button() === 2){
  286.             this.keyboard._proxy.ToggleRemote(function(){});
  287.         }
  288.         return Applet.Applet.prototype._onButtonPressEvent.call(this, actor, event);
  289.     },
  290.  
  291.     on_applet_clicked: function(event) {
  292.         this.menu.toggle();
  293.     },
  294.  
  295.     _onScrollEvent: function(actor, event) {
  296.         //adjust screen brightness on scroll
  297.         let direction = event.get_scroll_direction();
  298.         if (direction == Clutter.ScrollDirection.UP) {
  299.             this.brightness._proxy.StepUpRemote(function(){});
  300.         } else if (direction == Clutter.ScrollDirection.DOWN) {
  301.             this.brightness._proxy.StepDownRemote(function(){});
  302.         }
  303.         this.brightness._getBrightnessForcedUpdate();
  304.     },
  305.  
  306.     _getDeviceStatus: function(device) {
  307.         let status = ""
  308.         let [device_id, vendor, model, device_type, icon, percentage, state, seconds] = device;
  309.  
  310.         let time = Math.round(seconds / 60);
  311.         let minutes = time % 60;
  312.         let hours = Math.floor(time / 60);
  313.  
  314.         if (state == UPDeviceState.CHARGING) {
  315.             if (time == 0) {
  316.                 status = _("Charging");
  317.             }
  318.             else if (time > 60) {
  319.                 if (minutes == 0) {
  320.                     status = ngettext("Charging - %d hour until fully charged", "Charging - %d hours until fully charged", hours).format(hours);
  321.                 }
  322.                 else {
  323.                     /* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
  324.                     let template = _("Charging - %d %s %d %s until fully charged");
  325.                     status = template.format (hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes));
  326.                 }
  327.             }
  328.             else {
  329.                 status = ngettext("Charging - %d minute until fully charged", "Charging - %d minutes until fully charged", minutes).format(minutes);
  330.             }
  331.         }
  332.         else if (state == UPDeviceState.FULLY_CHARGED) {
  333.             status = _("Fully charged");
  334.         }
  335.         else {
  336.             if (time == 0) {
  337.                 status = _("Using battery power");
  338.             }
  339.             else if (time > 60) {
  340.                 if (minutes == 0) {
  341.                     status = ngettext("Using battery power - %d hour remaining", "Using battery power - %d hours remaining", hours).format(hours);
  342.                 }
  343.                 else {
  344.                     /* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
  345.                     let template = _("Using battery power - %d %s %d %s remaining");
  346.                     status = template.format (hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes));
  347.                 }
  348.             }
  349.             else {
  350.                 status = ngettext("Using battery power - %d minute remaining", "Using battery power - %d minutes remaining", minutes).format(minutes);
  351.             }
  352.         }
  353.  
  354.         return status;
  355.     },
  356.  
  357.     on_panel_height_changed: function() {
  358.         if (this._proxy)
  359.             this._devicesChanged();
  360.     },
  361.  
  362.     showDeviceInPanel: function(device) {
  363.         let [device_id, vendor, model, device_type, icon, percentage, state, seconds] = device;
  364.         let status = this._getDeviceStatus(device);
  365.         this.set_applet_tooltip(status);
  366.         let labelText = "";
  367.         if (this.labelinfo == "nothing") {
  368.             ;
  369.         }
  370.         else if (this.labelinfo == "time" && seconds != 0) {
  371.             let time = Math.round(seconds / 60);
  372.             let minutes = time % 60;
  373.             let hours = Math.floor(time / 60);
  374.             labelText = C_("time of battery remaining", "%d:%02d").format(hours,minutes);
  375.         }
  376.         else if (this.labelinfo == "percentage" || (this.labelinfo == "percentage_time" && seconds == 0)) {
  377.             labelText = C_("percent of battery remaining", "%d%%").format(Math.round(percentage));
  378.         }
  379.         else if (this.labelinfo == "percentage_time") {
  380.             let time = Math.round(seconds / 60);
  381.             let minutes = Math.floor(time % 60);
  382.             let hours = Math.floor(time / 60);
  383.             labelText = C_("percent of battery remaining", "%d%%").format(Math.round(percentage)) + " (" +
  384.                 C_("time of battery remaining", "%d:%02d").format(hours,minutes) + ")";
  385.         }
  386.         this.set_applet_label(labelText);
  387.         if (this.labelinfo != "nothing") {
  388.             this._applet_label.set_margin_left(1.0);
  389.         }
  390.  
  391.         if(icon){
  392.             if(this.panel_icon_name != icon){
  393.                 this.panel_icon_name = icon;
  394.                 this.set_applet_icon_symbolic_name('battery-full');
  395.                 let gicon = Gio.icon_new_for_string(icon);
  396.                 this._applet_icon.gicon = gicon;
  397.             }
  398.         }
  399.         else {
  400.             if (this.panel_icon_name != 'battery-full') {
  401.                 this.panel_icon_name = 'battery-full';
  402.                 this.set_applet_icon_symbolic_name('battery-full');
  403.             }
  404.         }
  405.     },
  406.  
  407.     _devicesChanged: function() {
  408.  
  409.         this._devices = [];
  410.         this._primaryDevice = null;
  411.  
  412.         // Identify the primary battery device
  413.         this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(device, error) {
  414.             if (error) {
  415.                 this._primaryDeviceId = null;
  416.             }
  417.             else {
  418.                 if (device.length == 1) {
  419.                     // Primary Device can be an array of primary devices rather than a single device, in that case, take the first one.
  420.                     device = device[0];
  421.                 }
  422.                 let [device_id, vendor, model, device_type, icon, percentage, state, seconds] = device
  423.                 this._primaryDeviceId = device_id;
  424.             }
  425.         }));
  426.  
  427.         // Scan battery devices
  428.         this._proxy.GetDevicesRemote(Lang.bind(this, function(result, error) {
  429.             this._deviceItems.forEach(function(i) { i.destroy(); });
  430.             this._deviceItems = [];
  431.             let devices_stats = [];
  432.  
  433.             if (!error) {
  434.                 let devices = result[0];
  435.                 let position = 0;
  436.                 for (let i = 0; i < devices.length; i++) {
  437.                     let [device_id, vendor, model, device_type, icon, percentage, state, seconds] = devices[i];
  438.  
  439.                     // Ignore AC_POWER devices
  440.                     if (device_type == UPDeviceType.AC_POWER)
  441.                         continue;
  442.  
  443.                     // Ignore devices which state is unknown
  444.                     if (state == UPDeviceState.UNKNOWN)
  445.                         continue;
  446.  
  447.                     let stats = "%s (%d%%)".format(deviceTypeToString(device_type), percentage);
  448.                     devices_stats.push(stats);
  449.                     this._devices.push(devices[i]);
  450.  
  451.                     if (this._primaryDeviceId == null || this._primaryDeviceId == device_id) {
  452.                         // Info for the primary battery (either the primary device, or any battery device if there is no primary device)
  453.                         if (device_type == UPDeviceType.BATTERY && this._primaryDevice == null) {
  454.                             this._primaryDevice = devices[i];
  455.                         }
  456.                     }
  457.  
  458.                     let status = this._getDeviceStatus(devices[i]);
  459.                     let item = new DeviceItem (devices[i], status);
  460.                     this.menu.addMenuItem(item, position);
  461.                     this.num_devices = this.num_devices + 1;
  462.                     this._deviceItems.push(item);
  463.                     position++;
  464.                 }
  465.             }
  466.             else {
  467.                 global.log(error);
  468.             }
  469.  
  470.             // The menu is built. Below, we update the information present in the panel (icon, tooltip and label)
  471.             this.set_applet_enabled(true);
  472.             let panel_device = null;
  473.             if (this._primaryDevice != null) {
  474.                 this.showDeviceInPanel(this._primaryDevice);
  475.             }
  476.             else {
  477.                 if (this._devices.length == 1) {
  478.                     this.showDeviceInPanel(this._devices[0]);
  479.                 }
  480.                 else if (this._devices.length > 1) {
  481.                     // Show a summary
  482.                     this.set_applet_tooltip(devices_stats.join(", "));
  483.                     this.set_applet_label("");
  484.                     let icon = this._proxy.Icon;
  485.                     if(icon) {
  486.                         if (icon != this.panel_icon_name){
  487.                             this.panel_icon_name = icon;
  488.                             this.set_applet_icon_symbolic_name('battery-full');
  489.                             let gicon = Gio.icon_new_for_string(icon);
  490.                             this._applet_icon.gicon = gicon;
  491.                         }
  492.                     }
  493.                     else {
  494.                         if (this.panel_icon_name != 'battery-full') {
  495.                             this.panel_icon_name = 'battery-full';
  496.                             this.set_applet_icon_symbolic_name('battery-full');
  497.                         }
  498.                     }
  499.                 }
  500.                 else {
  501.                     // If there are no battery devices, show brightness info or disable the applet
  502.                     if (this.brightness.actor.visible) {
  503.                         // Show the brightness info
  504.                         this.set_applet_tooltip(_("Brightness"));
  505.                         this.panel_icon_name = 'display-brightness';
  506.                         this.set_applet_icon_symbolic_name('display-brightness');
  507.                     }
  508.                     else if (this.keyboard.actor.visible) {
  509.                         // Show the brightness info
  510.                         this.set_applet_tooltip(_("Keyboard backlight"));
  511.                         this.panel_icon_name = 'keyboard-brightness';
  512.                         this.set_applet_icon_symbolic_name('keyboard-brightness');
  513.                     }
  514.                     else {
  515.                         // Disable the applet
  516.                         this.set_applet_enabled(false);
  517.                     }
  518.                 }
  519.             }
  520.  
  521.         }));
  522.     },
  523.  
  524.     on_applet_removed_from_panel: function() {
  525.         Main.systrayManager.unregisterId(this.metadata.uuid);
  526.     }
  527. };
  528.  
  529. function main(metadata, orientation, panel_height, instanceId) {
  530.     let myApplet = new MyApplet(metadata, orientation, panel_height, instanceId);
  531.     return myApplet;
  532. }
Add Comment
Please, Sign In to add comment