New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial support for 'com.canonical.Unity.LauncherEntry' APIs #590
Closed
Closed
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
23d293d
Implement a notification badge in MyAppIcon
azzar1 93358fa
Ellipsize if the number is too big.
azzar1 b67154f
Implement the dbus backed for the unity launcher api.
azzar1 0027f74
remove .vscode directory
azzar1 11113a2
Use var instead of const.
azzar1 b79ce26
Remove trailing whitespaces
azzar1 52fa8b3
Support older version of gjs.
azzar1 4f628f5
Merge remote-tracking branch 'origin/master' into add-counters
azzar1 2bed1e1
Support progress bar.
azzar1 b273d8c
Add drawRoundedLine to utils.js
azzar1 5a370bb
Minor changes after review
azzar1 8932f87
Change the default color
azzar1 File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,12 +5,14 @@ const GdkPixbuf = imports.gi.GdkPixbuf | |
const Gio = imports.gi.Gio; | ||
const GLib = imports.gi.GLib; | ||
const Gtk = imports.gi.Gtk; | ||
const Pango = imports.gi.Pango; | ||
const Signals = imports.signals; | ||
const Lang = imports.lang; | ||
const Meta = imports.gi.Meta; | ||
const Shell = imports.gi.Shell; | ||
const St = imports.gi.St; | ||
const Mainloop = imports.mainloop; | ||
const Cairo = imports.cairo; | ||
|
||
// Use __ () and N__() for the extension gettext domain, and reuse | ||
// the shell domain with the default _() and N_() | ||
|
@@ -99,6 +101,7 @@ var MyAppIcon = new Lang.Class({ | |
this.monitorIndex = monitorIndex; | ||
this._signalsHandler = new Utils.GlobalSignalsHandler(); | ||
this._nWindows = 0; | ||
this._remoteEntries = []; | ||
|
||
this.parent(app, iconParams); | ||
|
||
|
@@ -132,6 +135,8 @@ var MyAppIcon = new Lang.Class({ | |
} | ||
|
||
this._dots = null; | ||
this._progressOverlayArea = null; | ||
this._progress = 0; | ||
|
||
let keys = ['apply-custom-theme', | ||
'custom-theme-running-dots', | ||
|
@@ -156,6 +161,7 @@ var MyAppIcon = new Lang.Class({ | |
})); | ||
this._optionalScrollCycleWindows(); | ||
|
||
this._notificationBadge(); | ||
this._numberOverlay(); | ||
|
||
this._previewMenuManager = null; | ||
|
@@ -951,6 +957,169 @@ var MyAppIcon = new Lang.Class({ | |
cr.$dispose(); | ||
}, | ||
|
||
_notificationBadge: function() { | ||
this._notificationBadgeLabel = new St.Label(); | ||
this._notificationBadgeBin = new St.Bin({ | ||
child: this._notificationBadgeLabel, | ||
x_align: St.Align.END, y_align: St.Align.START, | ||
x_expand: true, y_expand: true | ||
}); | ||
this._notificationBadgeLabel.add_style_class_name('notification-badge'); | ||
this._notificationBadgeCount = 0; | ||
this._notificationBadgeBin.hide(); | ||
|
||
this._iconContainer.add_child(this._notificationBadgeBin); | ||
this._iconContainer.connect('allocation-changed', Lang.bind(this, this.updateNotificationBadge)); | ||
}, | ||
|
||
updateNotificationBadge: function() { | ||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; | ||
let [minWidth, natWidth] = this._iconContainer.get_preferred_width(-1); | ||
let logicalNatWidth = natWidth / scaleFactor; | ||
let font_size = Math.max(10, Math.round(logicalNatWidth / 5)); | ||
let margin_left = Math.round(logicalNatWidth / 4); | ||
|
||
this._notificationBadgeLabel.set_style( | ||
'font-size: ' + font_size + 'px;' + | ||
'margin-left: ' + margin_left + 'px;' | ||
); | ||
|
||
this._notificationBadgeBin.width = Math.round(logicalNatWidth - margin_left); | ||
this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE; | ||
}, | ||
|
||
_notificationBadgeCountToText: function(count) { | ||
if (count <= 9999) { | ||
return count.toString(); | ||
} else if (count < 1e5) { | ||
let thousands = count / 1e3; | ||
return thousands.toFixed(1).toString() + "k"; | ||
} else if (count < 1e6) { | ||
let thousands = count / 1e3; | ||
return thousands.toFixed(0).toString() + "k"; | ||
} else if (count < 1e8) { | ||
let millions = count / 1e6; | ||
return millions.toFixed(1).toString() + "M"; | ||
} else if (count < 1e9) { | ||
let millions = count / 1e6; | ||
return millions.toFixed(0).toString() + "M"; | ||
} else { | ||
let billions = count / 1e9; | ||
return billions.toFixed(1).toString() + "B"; | ||
} | ||
}, | ||
|
||
setNotificationBadge: function(count) { | ||
this._notificationBadgeCount = count; | ||
let text = this._notificationBadgeCountToText(count); | ||
this._notificationBadgeLabel.set_text(text); | ||
}, | ||
|
||
toggleNotificationBadge: function(activate) { | ||
if (activate && this._notificationBadgeCount > 0) { | ||
this.updateNotificationBadge(); | ||
this._notificationBadgeBin.show(); | ||
} | ||
else | ||
this._notificationBadgeBin.hide(); | ||
}, | ||
|
||
_showProgressOverlay: function() { | ||
if (this._progressOverlayArea) { | ||
this._updateProgressOverlay(); | ||
return; | ||
} | ||
|
||
this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true}); | ||
this._progressOverlayArea.connect('repaint', Lang.bind(this, function() { | ||
this._drawProgressOverlay(this._progressOverlayArea); | ||
})); | ||
|
||
this._iconContainer.add_child(this._progressOverlayArea); | ||
this._updateProgressOverlay(); | ||
}, | ||
|
||
_hideProgressOverlay: function() { | ||
if (this._progressOverlayArea) | ||
this._progressOverlayArea.destroy(); | ||
this._progressOverlayArea = null; | ||
}, | ||
|
||
_updateProgressOverlay: function() { | ||
if (this._progressOverlayArea) | ||
this._progressOverlayArea.queue_repaint(); | ||
}, | ||
|
||
_drawProgressOverlay: function(area) { | ||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; | ||
let [surfaceWidth, surfaceHeight] = area.get_surface_size(); | ||
let cr = area.get_context(); | ||
|
||
let iconSize = this.icon.iconSize * scaleFactor; | ||
|
||
let x = Math.floor((surfaceWidth - iconSize) / 2); | ||
let y = Math.floor((surfaceHeight - iconSize) / 2); | ||
|
||
let lineWidth = Math.floor(1.0 * scaleFactor); | ||
let padding = Math.floor(iconSize * 0.05); | ||
let width = iconSize - 2.0*padding; | ||
let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize)); | ||
x += padding; | ||
y += iconSize - height - padding; | ||
|
||
cr.setLineWidth(lineWidth); | ||
|
||
// Draw the outer stroke | ||
let stroke = new Cairo.LinearGradient(0, y, 0, y + height); | ||
let fill = null; | ||
stroke.addColorStopRGBA(0.5, 0.5, 0.5, 0.5, 0.1); | ||
stroke.addColorStopRGBA(0.9, 0.8, 0.8, 0.8, 0.4); | ||
Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); | ||
|
||
// Draw the background | ||
x += lineWidth; | ||
y += lineWidth; | ||
width -= 2.0*lineWidth; | ||
height -= 2.0*lineWidth; | ||
|
||
stroke = Cairo.SolidPattern.createRGBA(0.20, 0.20, 0.20, 0.9); | ||
fill = new Cairo.LinearGradient(0, y, 0, y + height); | ||
fill.addColorStopRGBA(0.4, 0.25, 0.25, 0.25, 1.0); | ||
fill.addColorStopRGBA(0.9, 0.35, 0.35, 0.35, 1.0); | ||
Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); | ||
|
||
// Draw the finished bar | ||
x += lineWidth; | ||
y += lineWidth; | ||
width -= 2.0*lineWidth; | ||
height -= 2.0*lineWidth; | ||
|
||
let finishedWidth = Math.ceil(this._progress * width); | ||
stroke = Cairo.SolidPattern.createRGBA(0.8, 0.8, 0.8, 1.0); | ||
fill = Cairo.SolidPattern.createRGBA(0.9, 0.9, 0.9, 1.0); | ||
|
||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) | ||
Utils.drawRoundedLine(cr, x + lineWidth/2.0 + width - finishedWidth, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); | ||
else | ||
Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); | ||
|
||
cr.$dispose(); | ||
}, | ||
|
||
setProgress: function(progress) { | ||
this._progress = Math.min(Math.max(progress, 0.0), 1.0); | ||
this._updateProgressOverlay(); | ||
}, | ||
|
||
toggleProgressOverlay: function(activate) { | ||
if (activate) { | ||
this._showProgressOverlay(); | ||
} | ||
else { | ||
this._hideProgressOverlay(); | ||
} | ||
}, | ||
|
||
_numberOverlay: function() { | ||
// Add label for a Hot-Key visual aid | ||
this._numberOverlayLabel = new St.Label(); | ||
|
@@ -1102,7 +1271,68 @@ var MyAppIcon = new Lang.Class({ | |
// nautilus desktop window. | ||
getInterestingWindows: function() { | ||
return getInterestingWindows(this.app, this._dtdSettings, this.monitorIndex); | ||
} | ||
}, | ||
|
||
insertEntryRemote: function(remote) { | ||
if (!remote || this._remoteEntries.includes(remote)) | ||
return; | ||
|
||
this._remoteEntries.push(remote); | ||
this._selectEntryRemote(remote); | ||
}, | ||
|
||
removeEntryRemote: function(remote) { | ||
if (!remote || !this._remoteEntries.includes(remote)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. |
||
return; | ||
|
||
this._remoteEntries.splice(this._remoteEntries.indexOf(remote), 1); | ||
|
||
if (this._remoteEntries.length > 0) { | ||
this._selectEntryRemote(this._remoteEntries[this._remoteEntries.length-1]); | ||
} else { | ||
this.setNotificationBadge(0); | ||
this.toggleNotificationBadge(false); | ||
this.setProgress(0); | ||
this.toggleProgressOverlay(false); | ||
} | ||
}, | ||
|
||
_selectEntryRemote: function(remote) { | ||
if (!remote) | ||
return; | ||
|
||
this._signalsHandler.removeWithLabel('entry-remotes'); | ||
|
||
this._signalsHandler.addWithLabel('entry-remotes', [ | ||
remote, | ||
'count-changed', | ||
Lang.bind(this, (remote, value) => { | ||
this.setNotificationBadge(value); | ||
}) | ||
], [ | ||
remote, | ||
'count-visible-changed', | ||
Lang.bind(this, (remote, value) => { | ||
this.toggleNotificationBadge(value); | ||
}) | ||
], [remote, | ||
'progress-changed', | ||
Lang.bind(this, (remote, value) => { | ||
this.setProgress(value); | ||
}) | ||
], [ | ||
remote, | ||
'progress-visible-changed', | ||
Lang.bind(this, (remote, value) => { | ||
this.toggleProgressOverlay(value); | ||
}) | ||
]); | ||
|
||
this.setNotificationBadge(remote.count()); | ||
this.toggleNotificationBadge(remote.countVisible()); | ||
this.setProgress(remote.progress()); | ||
this.toggleProgressOverlay(remote.progressVisible()); | ||
}, | ||
}); | ||
/** | ||
* Extend AppIconMenu | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@azzar1 I used your new script (thanks!), and got this running on Gnome 3.22.
This line is throwing an error for me, since Debian is still on mozJS 24.
Perhaps we can change
includes
(which is not supported until mozJS 52) with: