1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-01-05 11:14:11 +01:00

Basic Songbird 1.9a support.

--HG--
rename : xulmus/AUTHORS => melodactyl/AUTHORS
rename : xulmus/Makefile => melodactyl/Makefile
rename : xulmus/NEWS => melodactyl/NEWS
rename : xulmus/TODO => melodactyl/TODO
rename : xulmus/chrome.manifest => melodactyl/chrome.manifest
rename : xulmus/components/commandline-handler.js => melodactyl/components/commandline-handler.js
rename : xulmus/components/protocols.js => melodactyl/components/protocols.js
rename : xulmus/content/config.js => melodactyl/content/config.js
rename : xulmus/content/dactyl.dtd => melodactyl/content/dactyl.dtd
rename : xulmus/content/library.js => melodactyl/content/library.js
rename : xulmus/content/logo.png => melodactyl/content/logo.png
rename : xulmus/content/xulmus.xul => melodactyl/content/melodactyl.xul
rename : xulmus/content/player.js => melodactyl/content/player.js
rename : xulmus/content/xulmus.svg => melodactyl/content/xulmus.svg
rename : xulmus/contrib/vim/Makefile => melodactyl/contrib/vim/Makefile
rename : xulmus/contrib/vim/ftdetect/xulmus.vim => melodactyl/contrib/vim/ftdetect/melodactyl.vim
rename : xulmus/contrib/vim/mkvimball.txt => melodactyl/contrib/vim/mkvimball.txt
rename : xulmus/contrib/vim/syntax/xulmus.vim => melodactyl/contrib/vim/syntax/melodactyl.vim
rename : xulmus/defaults/preferences/dactyl.js => melodactyl/defaults/preferences/dactyl.js
rename : xulmus/install.rdf => melodactyl/install.rdf
rename : xulmus/locale/en-US/all.xml => melodactyl/locale/en-US/all.xml
rename : xulmus/locale/en-US/autocommands.xml => melodactyl/locale/en-US/autocommands.xml
rename : xulmus/locale/en-US/browsing.xml => melodactyl/locale/en-US/browsing.xml
rename : xulmus/locale/en-US/dactyl.dtd => melodactyl/locale/en-US/dactyl.dtd
rename : xulmus/locale/en-US/gui.xml => melodactyl/locale/en-US/gui.xml
rename : xulmus/locale/en-US/intro.xml => melodactyl/locale/en-US/intro.xml
rename : xulmus/locale/en-US/player.xml => melodactyl/locale/en-US/player.xml
rename : xulmus/locale/en-US/tabs.xml => melodactyl/locale/en-US/tabs.xml
rename : xulmus/skin/icon.png => melodactyl/skin/icon.png
This commit is contained in:
Kris Maglione
2010-10-02 10:44:19 -04:00
parent c0a5a680b8
commit a59d88fee7
40 changed files with 84 additions and 79 deletions

6
melodactyl/AUTHORS Normal file
View File

@@ -0,0 +1,6 @@
Main developer/Project founder:
* Prathyush Thota <prathyushthota@gmail.com>
Developers:
* Martin Stubenschrott (stubenschrott@vimperator.org)
* Doug Kearns (dougkearns@gmail.com)

11
melodactyl/Makefile Normal file
View File

@@ -0,0 +1,11 @@
#### configuration
NAME = melodactyl
FIREFOX ?= songbird
HOSTAPP ?= $(SONGBIRD)
PROFILEPATHS ?= "$$HOME/.songbird" \
"$$HOME/Library/Songbird" \
"$$APPDATA/Songbird"
include ../common/Makefile

22
melodactyl/NEWS Executable file
View File

@@ -0,0 +1,22 @@
2009-XX-XX:
* version 0.2pre
* asciidoc is no longer required to build Xulmus
* The help system is newly modularized
* add [c]:silent[c]
* add [j]$MY_XULMUSRC[j]
* add [m]'[m] and [m]"[m] local marks
* add [m]w[m] and [m]W[m] Normal mode mappings for symmetry with [m]o[m]/[m]O[m] and [m]t[m]/[m]T[m]
* add [c]:messclear[c]
* add 'maxitems'
* [c]:dialog {subscribe|newsmartplaylist}[c]
* add [c]:displaypane[c] and [c]:dpclose[c]
* rename [c]:filter[c] to [c]:queue[c] and [c]:Filter[c] to [c]:filter[c]
* add 'repeat' and 'shuffle'
* add 'jsdebugger' option - switch on/off javascript debugger service
* add "addons", "downloads", "extoptions" and "help" to the 'activate' option.
2009-03-28:
* version 0.1
* first public release
// vim: set filetype=asciidoc:

24
melodactyl/TODO Normal file
View File

@@ -0,0 +1,24 @@
Priority list:
1-9 as in Vim (9 = required for next release, 5 = would be nice, 1 = probably not)
BUGS:
- broken commands:
- :tabduplicate
- :open songbird-internal-search searchString (broken because SB intercepts queries to this engine)
- <C-^> only works between browser tabs not the media tab
- numbered tabs
- command-line option handling is broken in Xulmus only - it used to work.
FEATURES:
9 '?' - Reusing '/'.
8 Merge with SongBird's sanitizer implementation.
8 Playlist/SmartPlaylist operations & meta-data operations.
8 Sort-View commands.
7 Queue view.
7 j/k - for browsing through the visible view.
7 extended hint mode for opening links in FF.
6 :tqueue, :lqueue etc.
5 make Player mode commands work in the Mini-Player.
5 Check for default extensions and add commands for them. Ex. Last.fm, Seeqpod e.t.c
Wouldn't these be provided as Xulmus plugins like Pentadactyl does? --djk
5 tagging tracks for manipulation by commands

View File

@@ -0,0 +1,37 @@
# Songbird
content melodactyl content/
skin melodactyl classic/1.0 skin/
locale melodactyl en-US locale/en-US/
locale dactyl en-US ../common/locale/en-US/
content dactyl ../common/content/
resource dactyl ../common/modules/
skin dactyl classic/1.0 ../common/skin/
override chrome://dactyl/content/dactyl.dtd chrome://melodactyl/content/dactyl.dtd
override chrome://dactyl/content/config.js chrome://melodactyl/content/config.js
overlay chrome://songbird/content/xul/layoutBaseOverlay.xul chrome://melodactyl/content/melodactyl.xul
overlay chrome://songbird/content/xul/layoutBaseOverlay.xul chrome://dactyl/content/dactyl.xul
#component {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69} components/commandline-handler.js
#contract @mozilla.org/commandlinehandler/general-startup;1?type=melodactyl {16dc34f7-6d22-4aa4-a67f-2921fb5dcb69}
#category command-line-handler m-melodactyl @mozilla.org/commandlinehandler/general-startup;1?type=melodactyl
#
#component {c1b67a07-18f7-4e13-b361-2edcc35a5a0d} components/protocols.js
#contract @mozilla.org/network/protocol;1?name=chrome-data {c1b67a07-18f7-4e13-b361-2edcc35a5a0d}
#component {9c8f2530-51c8-4d41-b356-319e0b155c44} components/protocols.js
#contract @mozilla.org/network/protocol;1?name=dactyl {9c8f2530-51c8-4d41-b356-319e0b155c44}
#component {f4506a17-5b4d-4cd9-92d4-2eb4630dc388} components/protocols.js
#contract @dactyl.googlecode.com/base/xpc-interface-shim {f4506a17-5b4d-4cd9-92d4-2eb4630dc388}
#component {81495d80-89ee-4c36-a88d-ea7c4e5ac63f} components/protocols.js
#contract @mozilla.org/network/protocol/about;1?what=melodactyl {81495d80-89ee-4c36-a88d-ea7c4e5ac63f}
#overlay chrome://songbird/content/xul/layoutWithBrowserOverlay.xul chrome://xulmus/content/xulmus.xul
#overlay chrome://songbird/content/xul/layoutWithBrowserOverlay.xul chrome://dactyl/content/dactyl.xul
#overlay chrome://songbird/content/xul/layoutWithoutBrowserOverlay.xul chrome://xulmus/content/xulmus.xul
#overlay chrome://songbird/content/xul/layoutWithoutBrowserOverlay.xul chrome://dactyl/content/dactyl.xul
#overlay windowtype:Songbird:Main chrome://dactyl/content/dactyl.xul
#overlay windowtype:Songbird:Main chrome://xulmus/content/xulmus.xul

View File

@@ -0,0 +1 @@
../../common/components/commandline-handler.js

View File

@@ -0,0 +1 @@
../../common/components/protocols.js

View File

@@ -0,0 +1,308 @@
// Copyright (c) 2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
// Copyright (c) 2009 by Prathyush Thota <prathyushthota@gmail.com>
// Copyright (c) 2009 by Doug Kearns <dougkearns@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
Components.utils.import("resource://gre/modules/utils.js"); // XXX
const Config = Module("config", ConfigBase, {
init: function init() {
init.supercall(this);
// TODO: mention this to SB devs, they seem keen to provide these
// functions to make porting from FF as simple as possible.
window.toJavaScriptConsole = function () {
toOpenWindowByType("global:console", "chrome://global/content/console.xul");
};
window.BrowserStop = function () {
SBGetBrowser().mCurrentBrowser.stop();
};
},
/*** required options, no checks done if they really exist, so be careful ***/
name: "Xulmus",
host: "Songbird",
/*** optional options, there are checked for existence and a fallback provided ***/
features: ["bookmarks", "hints", "marks", "history", "quickmarks", "session", "tabs", "player"],
defaults: {
guioptions: "mprb",
showtabline: 2,
titlestring: "Xulmus"
},
guioptions: {
m: ["Menubar", ["main-menubar"]],
T: ["Toolbar", ["nav-bar"]],
p: ["Player controls", ["player_wrapper"]]
},
get isPlayerWindow() SBGetBrowser().mCurrentTab == SBGetBrowser().mediaTab,
// focusContent() focuses this widget gSongbirdWindowController takes care of the focus.
get visualbellWindow() document.getElementById(this.mainWindowId),
styleableChrome: ["chrome://purplerain/content/xul/mainplayer.xul"],
autocommands: {
BookmarkAdd: "Triggered after a page is bookmarked",
ColorScheme: "Triggered after a color scheme has been loaded",
DOMLoad: "Triggered when a page's DOM content has fully loaded",
DownloadPost: "Triggered when a download has completed",
Fullscreen: "Triggered when the browser's fullscreen state changes",
LocationChange: "Triggered when changing tabs or when navigation to a new location",
PageLoadPre: "Triggered after a page load is initiated",
PageLoad: "Triggered when a page gets (re)loaded/opened",
ShellCmdPost: "Triggered after executing a shell command with :!cmd",
TrackChangePre: "Triggered before a playing track is changed",
TrackChange: "Triggered after a playing track has changed",
ViewChangePre: "Triggered before a sequencer view is changed",
ViewChange: "Triggered after a sequencer view is changed",
StreamStart: "Triggered after a stream has started",
StreamPause: "Triggered after a stream has paused",
StreamEnd: "Triggered after a stream has ended",
StreamStop: "Triggered after a stream has stopped",
Enter: "Triggered after Songbird starts",
LeavePre: "Triggered before exiting Songbird, just before destroying each module",
Leave: "Triggered before exiting Songbird",
},
// TODO: remove those which don't make sense, can't be provided.
dialogs: {
about: ["About Songbird",
function () { window.openDialog("chrome://songbird/content/xul/about.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
addons: ["Manage Add-ons",
function () { SBOpenPreferences("paneAddons"); }],
checkupdates: ["Check for updates",
function () { window.checkForUpdates(); }],
cleardata: ["Clear private data",
function () { Sanitizer.showUI(); }],
cookies: ["List your cookies",
function () { window.toOpenWindowByType("Browser:Cookies", "chrome://browser/content/preferences/cookies.xul", "chrome,dialog=no,resizable"); }],
console: ["JavaScript console",
function () { window.toJavaScriptConsole(); }],
dominspector: ["DOM Inspector",
function () { try { window.inspectDOMDocument(content.document); } catch (e) { dactyl.echoerr("DOM Inspector extension not installed"); } }],
downloads: ["Manage Downloads",
function () { window.toOpenWindowByType("Download:Manager", "chrome://mozapps/content/downloads/downloads.xul", "chrome,dialog=no,resizable"); }],
jumpto: ["Jump to a media item",
function () { onJumpToFileKey(); }],
newsmartplaylist: ["Open the file selector dialog",
function () { SBNewSmartPlaylist(); }],
openfile: ["Open the file selector dialog",
function () { SBFileOpen(); }],
pagesource: ["View page source",
function () { window.BrowserViewSourceOfDocument(content.document); }],
places: ["Places Organizer: Manage your bookmarks and history",
function () { PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_BOOKMARKS); }],
preferences: ["Show Songbird preferences dialog",
function () { window.openPreferences(); }],
printsetup: ["Setup the page size and orientation before printing",
function () { PrintUtils.showPageSetup(); }],
print: ["Show print dialog",
function () { PrintUtils.print(); }],
saveframe: ["Save frame to disk",
function () { window.saveFrameDocument(); }],
savepage: ["Save page to disk",
function () { window.saveDocument(window.content.document); }],
searchengines: ["Manage installed search engines",
function () { window.openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
selectionsource: ["View selection source",
function () { buffer.viewSelectionSource(); }],
subscribe: ["Add a new subscription",
function () { SBSubscribe(); }]
},
focusChange: function () {
// Switch to -- PLAYER -- mode for Songbird Media Player.
if (config.isPlayerWindow)
dactyl.mode = modes.PLAYER;
else
dactyl.mode = modes.NORMAL;
},
hasTabbrowser: true,
// FIXME: unless I'm seeing double in in the wee small hours gBrowser is
// first set from getBrowser which they've deprecated in FF.
get tabbrowser() window.getBrowser(),
get browser() window.getBrowser(),
modes: [["PLAYER", { char: "p" }]],
removeTab: function (tab) {
if (config.tabbrowser.mTabs.length > 1)
config.tabbrowser.removeTab(tab);
else {
if (buffer.URL != "about:blank" || window.getWebNavigation().sessionHistory.count > 0) {
dactyl.open("about:blank", dactyl.NEW_BACKGROUND_TAB);
config.tabbrowser.removeTab(tab);
}
else
dactyl.beep();
}
},
scripts: [
"browser",
"bookmarks",
"history",
"quickmarks",
"tabs",
"player",
"library"
],
// FIXME: tab arg and media tab exception?
stop: function (tab) {
SBGetBrowser().mCurrentBrowser.stop();
}
}, {
/**
* Shows or hides the main service pane.
*
* @param {boolean} value Show the service pane if true, hide it if false.
*/
showServicePane: function (value) {
const key = "splitter.servicepane_splitter.was_collapsed";
gServicePane.open = value;
SBDataSetBoolValue(key, gServicePane.open);
},
/**
* Opens the display panel with the specified <b>id<b>.
*
* @param {string} id The ID of the display pane.
*/
openDisplayPane: function (id) {
if (id == "servicepane")
this.showServicePane(true);
else {
let pane = document.getElementById(id);
let manager = services.get("displayPaneManager");
let paneinfo = manager.getPaneInfo(pane._lastURL.stringValue);
if (!paneinfo)
paneinfo = manager.defaultPaneInfo;
pane.loadContent(paneinfo);
}
},
/**
* Closes the display panel with the specified <b>id</b>
*
* @param {string} id The ID of the display pane.
*/
closeDisplayPane: function (id) {
if (id == "servicepane")
this.showServicePane(false);
else
document.getElementById(id).hide();
},
// FIXME: best way to format these args? Hyphenated? One word like :dialog?
/**
* @property {object} A map of display pane command argument strings to
* panel element IDs.
*/
displayPanes: {
"service pane left": "servicepane",
"content pane bottom": "displaypane_contentpane_bottom",
"service pane bottom": "displaypane_servicepane_bottom",
"right sidebar": "displaypane_right_sidebar"
}
}, {
commands: function () {
commands.add(["dpcl[ose]"],
"Close a display pane",
function (args) {
let arg = args.literalArg;
if (arg in Config.displayPanes)
Config.closeDisplayPane(Config.displayPanes[arg]);
else
dactyl.echoerr("E475: Invalid argument: " + arg);
},
{
argCount: "1",
completer: function (context) completion.displayPane(context),
literal: 0
});
// TODO: this should accept a second arg to specify content
commands.add(["displayp[ane]", "dp[ane]", "dpope[n]"],
"Open a display pane",
function (args) {
let arg = args.literalArg;
if (arg in Config.displayPanes)
Config.openDisplayPane(Config.displayPanes[arg]);
// TODO: focus when we have better key handling of these extended modes
else
dactyl.echoerr("E475: Invalid argument: " + arg);
},
{
argCount: "1",
completer: function (context) completion.displayPane(context),
literal: 0
});
commands.add(["pref[erences]", "prefs"],
"Show " + config.host + " preferences",
function (args) {
if (args.bang) { // open Songbird settings GUI dialog
dactyl.open("about:config",
(options["newtab"] && options.get("newtab").has("all", "prefs"))
? dactyl.NEW_TAB : dactyl.CURRENT_TAB);
}
else
window.openPreferences();
},
{
argCount: "0",
bang: true
});
},
completion: function () {
completion.displayPane = function (context) {
context.title = ["Display Pane"];
context.completions = Config.displayPanes; // FIXME: useful description etc
};
},
modes: function () {
this.ignoreKeys = {
"<Return>": modes.NORMAL | modes.INSERT,
"<Space>": modes.NORMAL | modes.INSERT,
"<Up>": modes.NORMAL | modes.INSERT,
"<Down>": modes.NORMAL | modes.INSERT
};
},
options: function () {
// TODO: SB doesn't explicitly support an offline mode. Should we? --djk
options.add(["online"],
"Set the 'work offline' option",
"boolean", true,
{
setter: function (value) {
const ioService = services.get("io");
ioService.offline = !value;
options.setPref("browser.offline", ioService.offline);
return value;
},
getter: function () !services.get("io").offline
});
},
services: function () {
services.add("displayPaneManager", "@songbirdnest.com/Songbird/DisplayPane/Manager;1", Ci.sbIDisplayPaneManager);
services.add("mediaPageManager", "@songbirdnest.com/Songbird/MediaPageManager;1", Ci.sbIMediaPageManager);
services.add("propertyManager","@songbirdnest.com/Songbird/Properties/PropertyManager;1", Ci.sbIPropertyManager);
services.addClass("mutablePropertyArray", "@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1",
Ci.sbIMutablePropertyArray);
}
});
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -0,0 +1,18 @@
<!ENTITY % dactylBranding SYSTEM "chrome://branding/locale/brand.dtd">
%dactylBranding;
<!ENTITY dactyl.mainWindow "mainplayer">
<!ENTITY dactyl.commandContainer "&dactyl.mainWindow;">
<!ENTITY dactyl.name "xulmus">
<!ENTITY dactyl.appName "Xulmus">
<!ENTITY dactyl.idName "XULMUS">
<!ENTITY dactyl.host "&brandShortName;">
<!ENTITY dactyl.hostbin "songbird">
<!ENTITY dactyl.fileExt "xulmus">
<!ENTITY dactyl.statusBefore "statusbar-display">
<!ENTITY dactyl.statusAfter "">
<!ENTITY xmlns.dactyl "http://vimperator.org/namespaces/liberator">
<!ENTITY xmlns.html "http://www.w3.org/1999/xhtml">
<!ENTITY xmlns.xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

View File

@@ -0,0 +1,64 @@
// Copyright (c) 2009 by Prathyush Thota <prathyushthota@gmail.com>
// Copyright (c) 2009 by Doug Kearns <dougkearns@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
// TODO: flesh this out
const Library = Module("library", {
init: function () {
this.MAIN_LIBRARY = LibraryUtils.mainLibrary;
},
/**
* Converts an XPCOM enumerator to a JavaScript array.
*
* @param {nsISimpleEnumerator|nsIStringEnumerator|nsIArray} enum The enumerator to convert.
* @returns {Array}
*/
_toJSArray: function _toJSArray(enum) ArrayConverter.JSArray(enum),
/**
* Returns an array of all the artist names in the main library.
*
* @returns {string[]}
*/
getArtists: function getArtists() this._toJSArray(this.MAIN_LIBRARY.getDistinctValuesForProperty(SBProperties.artistName)),
// FIXME: Prathyush do we really want to remove duplicates? If so, why not tracks too? --djk
/**
* Returns an array of all the album names for <b>artist</b> in the
* main library.
*
* @param {string} artist The artist's name.
* @returns {string[]}
*/
getAlbums: function getAlbums(artist) {
let albums = this._toJSArray(this.MAIN_LIBRARY.getItemsByProperty(SBProperties.artistName, artist))
.map(function (track) track.getProperty(SBProperties.albumName));
return util.Array.uniq(albums);
},
/**
* Returns an array of all the track names for <b>artist</b> and
* <b>album</b> in the main library.
*
* @param {string} artist The artist's name.
* @param {string} album The album's name.
* @returns {string[]}
*/
getTracks: function getTracks(artist, album) {
let properties = services.create("mutablePropertyArray");
properties.appendProperty(SBProperties.artistName, artist);
properties.appendProperty(SBProperties.albumName, album);
return this._toJSArray(this.MAIN_LIBRARY.getItemsByProperties(properties))
.map(function (track) track.getProperty(SBProperties.trackName));
}
}, {
}, {
});
// vim: set fdm=marker sw=4 ts=4 et:

BIN
melodactyl/content/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,52 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://xulmus/skin/xulmus.css" type="text/css"?>
<overlay id="xulmus"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:nc="http://home.netscape.com/NC-rdf#"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menupopup id="viewSidebarMenu">
<menuitem observes="xulmus-viewAddonsSidebar" label="Add-ons" accesskey="A"/>
<menuitem observes="xulmus-viewConsoleSidebar" label="Console" accesskey="C"/>
<menuitem observes="xulmus-viewDownloadsSidebar" label="Downloads" accesskey="D"/>
<menuitem observes="xulmus-viewPreferencesSidebar" label="Preferences" accesskey="P"/>
</menupopup>
<broadcasterset id="mainBroadcasterSet">
<broadcaster id="xulmus-viewAddonsSidebar"
autoCheck="false"
type="checkbox"
group="sidebar"
sidebarurl="chrome://mozapps/content/extensions/extensions.xul"
sidebartitle="Add-ons"
oncommand="toggleSidebar('xulmus-viewAddonsSidebar');"/>
<broadcaster id="xulmus-viewConsoleSidebar"
autoCheck="false"
type="checkbox"
group="sidebar"
sidebarurl="chrome://global/content/console.xul"
sidebartitle="Console"
oncommand="toggleSidebar('xulmus-viewConsoleSidebar');"/>
<broadcaster id="xulmus-viewDownloadsSidebar"
autoCheck="false"
type="checkbox"
group="sidebar"
sidebarurl="chrome://mozapps/content/downloads/downloads.xul"
sidebartitle="Downloads"
oncommand="toggleSidebar('xulmus-viewDownloadsSidebar');"/>
<broadcaster id="xulmus-viewPreferencesSidebar"
autoCheck="false"
type="checkbox"
group="sidebar"
sidebarurl="about:config"
sidebartitle="Preferences"
oncommand="toggleSidebar('xulmus-viewPreferencesSidebar');"/>
</broadcasterset>
</overlay>
<!-- vim: set fdm=marker sw=4 ts=4 et: -->

View File

@@ -0,0 +1,799 @@
// Copyright (c) 2009 by Prathyush Thota <prathyushthota@gmail.com>
// Copyright (c) 2009 by Doug Kearns <dougkearns@gmail.com>
//
// This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file.
const Player = Module("player", {
init: function init() {
this._lastSearchString = "";
this._lastSearchIndex = 0;
this._lastSearchView = this._currentView; //XXX
// Get the focus to the visible playlist first
//window._SBShowMainLibrary();
gMM.addListener(this._mediaCoreListener);
},
destroy: function destroy() {
gMM.removeListener(this._mediaCoreListener);
},
/**
* Moves the track position <b>interval</b> milliseconds forwards or
* backwards.
*
* @param {number} interval The time interval (ms) to move the track
* position.
* @param {boolean} direction The direction in which to move the track
* position, forward if true otherwise backwards.
* @private
*/
_seek: function _seek(interval, direction) {
let position = gMM.playbackControl ? gMM.playbackControl.position : 0;
player.seekTo(position + (direction ? interval : -interval));
},
/**
* Listens for media core events and in response dispatches the appropriate
* autocommand events.
* @private
*/
_mediaCoreListener: {
onMediacoreEvent: function (event) {
switch (event.type) {
case Ci.sbIMediacoreEvent.BEFORE_TRACK_CHANGE:
dactyl.log("Before track changed: " + event.data);
autocommands.trigger("TrackChangePre", { track: event.data });
break;
case Ci.sbIMediacoreEvent.TRACK_CHANGE:
autocommands.trigger("TrackChange", { track: event.data });
break;
case Ci.sbIMediacoreEvent.BEFORE_VIEW_CHANGE:
dactyl.log("Before view changed: " + event.data);
autocommands.trigger("ViewChangePre", { view: event.data });
break;
case Ci.sbIMediacoreEvent.VIEW_CHANGE:
dactyl.log("View changed: " + event.data);
autocommands.trigger("ViewChange", { view: event.data });
break;
case Ci.sbIMediacoreEvent.STREAM_START:
dactyl.log("Track started: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamStart", { track: gMM.sequencer.currentItem });
break;
case Ci.sbIMediacoreEvent.STREAM_PAUSE:
dactyl.log("Track paused: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamPause", { track: gMM.sequencer.currentItem });
break;
case Ci.sbIMediacoreEvent.STREAM_END:
dactyl.log("Track ended: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamEnd", { track: gMM.sequencer.currentItem });
break;
case Ci.sbIMediacoreEvent.STREAM_STOP:
dactyl.log("Track stopped: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamStop", { track: gMM.sequencer.currentItem });
break;
}
}
},
/** @property {sbIMediaListView} The current media list view. @private */
get _currentView() SBGetBrowser().currentMediaListView,
/**
* @property {number} The player volume in the range 0.0-1.0.
*/
get volume() gMM.volumeControl.volume,
set volume(value) {
gMM.volumeControl.volume = value;
},
/**
* Focuses the specified media item in the current media list view.
*
* @param {sbIMediaItem} mediaItem The media item to focus.
*/
focusTrack: function focusTrack(mediaItem) {
SBGetBrowser().mediaTab.mediaPage.highlightItem(this._currentView.getIndexForItem(mediaItem));
},
/**
* Plays the currently selected media item. If no item is selected the
* first item in the current media view is played.
*/
play: function play() {
// Check if there is any selection in place, else play first item of the visible view.
// TODO: this approach, or similar, should be generalised for all commands, PT? --djk
if (this._currentView.selection.count != 0)
gMM.sequencer.playView(this._currentView,
this._currentView.getIndexForItem(this._currentView.selection.currentMediaItem));
else
gMM.sequencer.playView(SBGetBrowser().currentMediaListView, 0);
this.focusTrack(gMM.sequencer.currentItem);
},
/**
* Stops playback of the currently playing media item.
*/
stop: function stop() {
gMM.sequencer.stop();
},
/**
* Plays the next media item in the current media view.
*/
next: function next() {
["cmd_control_next", "cmd_find_current_track"].forEach(gSongbirdWindowController.doCommand);
},
/**
* Plays the previous media item in the current media view.
*/
previous: function previous() {
["cmd_control_previous", "cmd_find_current_track"].forEach(gSongbirdWindowController.doCommand);
},
/**
* Toggles the play/pause status of the current media item.
*/
togglePlayPause: function togglePlayPause() {
["cmd_control_playpause", "cmd_find_current_track"].forEach(gSongbirdWindowController.doCommand);
},
/**
* Toggles the shuffle status of the sequencer.
*/
toggleShuffle: function toggleShuffle() {
if (gMM.sequencer.mode != gMM.sequencer.MODE_SHUFFLE)
gMM.sequencer.mode = gMM.sequencer.MODE_SHUFFLE;
else
gMM.sequencer.mode = gMM.sequencer.MODE_FORWARD;
},
// FIXME: not really toggling (depending on your definition) - good enough for now.
/**
* Toggles between the sequencer's three repeat modes: Repeat-One,
* Repeat-All and Repeat-None.
*/
toggleRepeat: function toggleRepeat() {
switch (gMM.sequencer.repeatMode) {
case gMM.sequencer.MODE_REPEAT_NONE:
gMM.sequencer.repeatMode = gMM.sequencer.MODE_REPEAT_ONE;
break;
case gMM.sequencer.MODE_REPEAT_ONE:
gMM.sequencer.repeatMode = gMM.sequencer.MODE_REPEAT_ALL;
break;
case gMM.sequencer.MODE_REPEAT_ALL:
gMM.sequencer.repeatMode = gMM.sequencer.MODE_REPEAT_NONE;
break;
default:
gMM.sequencer.repeatMode = gMM.sequencer.MODE_REPEAT_NONE;
break;
}
},
/**
* Seeks forward <b>interval</b> milliseconds in the currently playing
* track.
*
* @param {number} interval The time interval (ms) to advance the
* current track.
*/
seekForward: function seekForward(interval) {
this._seek(interval, true);
},
/**
* Seeks backwards <b>interval</b> milliseconds in the currently
* playing track.
*
* @param {number} interval The time interval (ms) to rewind the
* current track.
*/
seekBackward: function seekBackward(interval) {
this._seek(interval, false);
},
/**
* Seeks to a specific position in the currently playing track.
*
* @param {number} The new position (ms) in the track.
*/
seekTo: function seekTo(position) {
// FIXME: if not playing
if (!gMM.playbackControl)
this.play();
let min = 0;
let max = gMM.playbackControl.duration - 5000; // TODO: 5s buffer like cmus desirable?
gMM.playbackControl.position = util.Math.constrain(position, min, max);
},
/**
* Increases the volume by 5% of the maximum volume.
*/
increaseVolume: function increaseVolume() {
this.volume = util.Math.constrain(this.volume + 0.05, 0, 1);
},
/**
* Decreases the volume by 5% of the maximum volume.
*/
decreaseVolume: function decreaseVolume() {
this.volume = util.Math.constrain(this.volume - 0.05, 0, 1);
},
// TODO: Document what this buys us over and above cmd_find_current_track
/**
* Focuses the currently playing track.
*/
focusPlayingTrack: function focusPlayingTrack() {
this.focusTrack(gMM.sequencer.currentItem);
},
/**
* Searches the current media view for <b>str</b>
*
* @param {string} str The search string.
*/
searchView: function searchView(str) {
let search = _getSearchString(this._currentView);
let searchString = "";
if (search != "") // XXX
searchString = str + " " + search;
else
searchString = str;
this._lastSearchString = searchString;
let searchView = LibraryUtils.createStandardMediaListView(this._currentView.mediaList, searchString);
if (searchView.length) {
this._lastSearchView = searchView;
this._lastSearchIndex = 0;
this.focusTrack(searchView.getItemByIndex(this._lastSearchIndex));
}
else
dactyl.echoerr("E486 Pattern not found: " + searchString, commandline.FORCE_SINGLELINE);
},
/**
* Repeats the previous view search.
*
* @param {boolean} reverse Search in the reverse direction to the previous
* search.
*/
searchViewAgain: function searchViewAgain(reverse) {
function echo(str) {
this.timeout(function () {
commandline.echo(str, commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES | commandline.FORCE_SINGLELINE);
}, 0);
}
if (reverse) {
if (this._lastSearchIndex == 0) {
this._lastSearchIndex = this._lastSearchView.length - 1;
echo("Search hit TOP, continuing at BOTTOM");
}
else
this._lastSearchIndex = this._lastSearchIndex - 1;
}
else {
if (this._lastSearchIndex == (this._lastSearchView.length - 1)) {
this._lastSearchIndex = 0;
echo("Search hit BOTTOM, continuing at TOP");
}
else
this._lastSearchIndex = this._lastSearchIndex + 1;
}
// TODO: Implement for "?" --ken
commandline.echo("/" + this._lastSearchString, null, commandline.FORCE_SINGLELINE);
this.focusTrack(this._lastSearchView.getItemByIndex(this._lastSearchIndex));
},
/**
* The search dialog keypress callback.
*
* @param {string} str The contents of the search dialog.
*/
onSearchKeyPress: function onSearchKeyPress(str) {
if (options["incsearch"])
this.searchView(str);
},
/**
* The search dialog submit callback.
*
* @param {string} str The contents of the search dialog.
*/
onSearchSubmit: function onSearchSubmit(str) {
this.searchView(str);
},
/**
* The search dialog cancel callback.
*/
onSearchCancel: function onSearchCancel() {
// TODO: restore the view state if altered by an 'incsearch' search
},
/**
* Returns an array of all available playlists.
*
* @returns {sbIMediaList[]}
*/
getPlaylists: function getPlaylists() {
let mainLibrary = LibraryUtils.mainLibrary;
let playlists = [mainLibrary];
let listener = {
onEnumerationBegin: function () { },
onEnumerationEnd: function () { },
onEnumeratedItem: function (list, item) {
// FIXME: why are there null items and duplicates?
if (!playlists.some(function (list) list.name == item.name) && item.name != null)
playlists.push(item);
return Ci.sbIMediaListEnumerationListener.CONTINUE;
}
};
mainLibrary.enumerateItemsByProperty("http://songbirdnest.com/data/1.0#isList", "1", listener);
return playlists;
},
/**
* Plays the media item at <b>index</b> in <b>playlist</b>.
*
* @param {sbIMediaList} playlist
* @param {number} index
*/
playPlaylist: function playPlaylist(playlist, index) {
gMM.sequencer.playView(playlist.createView(), index);
},
/**
* Returns an array of all available media pages.
*
* @returns {sbIMediaPageInfo[]}
*/
getMediaPages: function getMediaPages() {
let list = SBGetBrowser().currentMediaPage.mediaListView.mediaList;
let pages = services.get("mediaPageManager").getAvailablePages(list);
return ArrayConverter.JSArray(pages).map(function (page) page.QueryInterface(Ci.sbIMediaPageInfo));
},
/**
* Loads the the specified media page into <b>view</b> with the given
* <b>list</b> of media items.
*
* @param {sbIMediaPage} page
* @param {sbIMediaList} list
* @param {sbIMediaView} view
*/
loadMediaPage: function loadMediaPage(page, list, view) {
services.get("mediaPageManager").setPage(list, page);
SBGetBrowser().loadMediaList(list, null, null, view, null);
},
/**
* Applys the specified <b>rating<b> to <b>mediaItem<b>.
*
* @param {sbIMediaItem} mediaItem The media item to rate.
* @param {number} rating The star rating (1-5).
*/
rateMediaItem: function rateMediaItem(mediaItem, rating) {
mediaItem.setProperty(SBProperties.rating, rating);
},
// TODO: add more fields, and generate the list dynamically. PT should the
// available fields reflect only the visible view fields or offer others? --djk
/**
* Sorts the current media view by <b>field</b> in the order specified by
* <b>ascending</b>.
*
* @param {string} field The sort field.
* @param {boolean} ascending If true sort in ascending order, otherwise in
* descending order.
*/
sortBy: function sortBy(field, ascending) {
let order = ascending ? "a" : "d";
let properties = services.create("mutablePropertyArray");
properties.strict = false;
switch (field) {
case "title":
properties.appendProperty(SBProperties.trackName, order);
break;
case "time":
properties.appendProperty(SBProperties.duration, order);
break;
case "artist":
properties.appendProperty(SBProperties.artistName, order);
break;
case "album":
properties.appendProperty(SBProperties.albumName, order);
break;
case "genre":
properties.appendProperty(SBProperties.genre, order);
break;
case "rating":
properties.appendProperty(SBProperties.rating, order);
break;
default:
properties.appendProperty(SBProperties.trackName, order);
break;
}
this._currentView.setSort(properties);
}
}, {
}, {
commandline: function () {
commandline.registerCallback("change", modes.SEARCH_VIEW_FORWARD, this.closure.onSearchKeyPress);
commandline.registerCallback("submit", modes.SEARCH_VIEW_FORWARD, this.closure.onSearchSubmit);
commandline.registerCallback("cancel", modes.SEARCH_VIEW_FORWARD, this.closure.onSearchCancel);
},
commands: function () {
commands.add(["f[ilter]"],
"Filter tracks based on keywords {genre/artist/album/track}",
function (args) {
let library = LibraryUtils.mainLibrary;
let view = LibraryUtils.createStandardMediaListView(LibraryUtils.mainLibrary, args.literalArg);
if (view.length == 0)
dactyl.echoerr("No Tracks matching the keywords");
else {
SBGetBrowser().loadMediaList(LibraryUtils.mainLibrary, null, null, view,
"chrome://songbird/content/mediapages/filtersPage.xul");
// TODO: make this this.focusTrack work ?
this.focusTrack(view.getItemByIndex(0));
}
},
{
argCount: "1",
literal: 0
//completer: function (context, args) completion.tracks(context, args);
});
commands.add(["load"],
"Load a playlist",
function (args) {
let arg = args.literalArg;
if (arg) {
// load the selected playlist/smart playlist
let playlists = player.getPlaylists();
for ([i, list] in Iterator(playlists)) {
if (util.compareIgnoreCase(arg, list.name) == 0) {
SBGetBrowser().loadMediaList(playlists[i]);
this.focusTrack(this._currentView.getItemByIndex(0));
return;
}
}
dactyl.echoerr("E475: Invalid argument: " + arg);
}
else {
// load main library if there are no args
_SBShowMainLibrary();
}
},
{
argCount: "?",
completer: function (context, args) completion.playlist(context, args),
literal: 0
});
// TODO: better off as a single command (:player play) or cmus compatible (:player-play)? --djk
commands.add(["playerp[lay]"],
"Play track",
function () { player.play(); });
commands.add(["playerpa[use]"],
"Pause/unpause track",
function () { player.togglePlayPause(); });
commands.add(["playern[ext]"],
"Play next track",
function () { player.next(); });
commands.add(["playerpr[ev]"],
"Play previous track",
function () { player.previous(); });
commands.add(["players[top]"],
"Stop track",
function () { player.stop(); });
commands.add(["see[k]"],
"Seek to a track position",
function (args) {
let arg = args[0];
// intentionally supports 999:99:99
if (!/^[+-]?(\d+[smh]?|(\d+:\d\d:|\d+:)?\d{2})$/.test(arg))
return void dactyl.echoerr("E475: Invalid argument: " + arg);
function ms(t, m) Math.abs(parseInt(t, 10) * { s: 1000, m: 60000, h: 3600000 }[m])
if (/:/.test(arg)) {
let [seconds, minutes, hours] = arg.split(":").reverse();
hours = hours || 0;
var value = ms(seconds, "s") + ms(minutes, "m") + ms(hours, "h");
}
else {
if (!/[smh]/.test(arg.substr(-1)))
arg += "s"; // default to seconds
value = ms(arg.substring(arg, arg.length - 1), arg.substr(-1));
}
if (/^[-+]/.test(arg))
arg[0] == "-" ? player.seekBackward(value) : player.seekForward(value);
else
player.seekTo(value);
},
{ argCount: "1" });
commands.add(["mediav[iew]"],
"Change the current media view",
function (args) {
// FIXME: is this a SB restriction? --djk
if (!SBGetBrowser().currentMediaPage)
return void dactyl.echoerr("Exxx: Can only set the media view from the media tab"); // XXX
let arg = args[0];
if (arg) {
let pages = player.getMediaPages();
for ([, page] in Iterator(pages)) {
if (util.compareIgnoreCase(arg, page.contentTitle) == 0) {
player.loadMediaPage(page, SBGetBrowser().currentMediaListView.mediaList,
SBGetBrowser().currentMediaListView);
return;
}
}
dactyl.echoerr("E475: Invalid argument: " + arg);
}
},
{
argCount: "1",
completer: function (context) completion.mediaView(context),
literal: 0
});
commands.add(["sort[view]"],
"Sort the current media view",
function (args) {
let order = args["-order"] || "up";
player.sortBy(args[0], order == "up");
},
{
argCount: "1",
completer: function (context) completion.mediaListSort(context),
options: [[["-order", "-o"], commands.OPTION_STRING,
function (arg) /^(up|down)$/.test(arg),
function () [["up", "Sort in ascending order"], ["down", "Sort in descending order"]]]]
});
// FIXME: use :add -q like cmus? (not very vim-like are it's multi-option commands) --djk
commands.add(["qu[eue]"],
"Queue tracks by artist/album/track",
function (args) {
let properties = services.create("mutablePropertyArray");
// args
switch (args.length) {
case 3:
properties.appendProperty(SBProperties.trackName, args[2]);
case 2:
properties.appendProperty(SBProperties.albumName, args[1]);
case 1:
properties.appendProperty(SBProperties.artistName, args[0]);
break;
default:
break;
}
let library = LibraryUtils.mainLibrary;
let mainView = library.createView();
gMM.sequencer.playView(mainView,
mainView.getIndexForItem(library.getItemsByProperties(properties).queryElementAt(0, Ci.sbIMediaItem)));
player.focusPlayingTrack();
},
{
argCount: "+",
completer: function (context, args) completion.song(context, args)
});
// TODO: maybe :vol! could toggle mute on/off? --djk
commands.add(["vol[ume]"],
"Set the volume",
function (args) {
let arg = args[0];
if (!/^[+-]?\d+$/.test(arg))
return void dactyl.echoerr("E488: Trailing characters");
let level = parseInt(arg, 10) / 100;
if (/^[+-]/.test(arg))
level = player.volume + level;
player.volume = util.Math.constrain(level, 0, 1);
},
{ argCount: "1" });
},
completion: function () {
completion.song = function song(context, args) {
// TODO: useful descriptions?
function map(list) list.map(function (i) [i, ""]);
let [artist, album] = [args[0], args[1]];
if (args.completeArg == 0) {
context.title = ["Artists"];
context.completions = map(library.getArtists());
}
else if (args.completeArg == 1) {
context.title = ["Albums by " + artist];
context.completions = map(library.getAlbums(artist));
}
else if (args.completeArg == 2) {
context.title = ["Tracks from " + album + " by " + artist];
context.completions = map(library.getTracks(artist, album));
}
};
completion.playlist = function playlist(context, args) {
context.title = ["Playlist", "Type"];
context.keys = { text: "name", description: "type" };
context.completions = player.getPlaylists();
};
completion.mediaView = function mediaView(context) {
context.title = ["Media View", "URL"];
context.anchored = false;
context.keys = { text: "contentTitle", description: "contentUrl" };
context.completions = player.getMediaPages();
};
completion.mediaListSort = function mediaListSort(context) {
context.title = ["Media List Sort Field", "Description"];
context.anchored = false;
context.completions = [["title", "Track name"], ["time", "Duration"], ["artist", "Artist name"],
["album", "Album name"], ["genre", "Genre"], ["rating", "Rating"]]; // FIXME: generate this list dynamically - see #sortBy
};
},
mappings: function () {
mappings.add([modes.PLAYER],
["x"], "Play track",
function () { player.play(); });
mappings.add([modes.PLAYER],
["z"], "Previous track",
function () { player.previous(); });
mappings.add([modes.PLAYER],
["c"], "Pause/unpause track",
function () { player.togglePlayPause(); });
mappings.add([modes.PLAYER],
["b"], "Next track",
function () { player.next(); });
mappings.add([modes.PLAYER],
["v"], "Stop track",
function () { player.stop(); });
mappings.add([modes.PLAYER],
["Q"], "Queue tracks by artist/album/track",
function () { commandline.open(":", "queue ", modes.EX); });
mappings.add([modes.PLAYER],
["f"], "Loads current view filtered by the keywords",
function () { commandline.open(":", "filter ", modes.EX); });
mappings.add([modes.PLAYER],
["i"], "Select current track",
function () { gSongbirdWindowController.doCommand("cmd_find_current_track"); });
mappings.add([modes.PLAYER],
["s"], "Toggle shuffle",
function () { player.toggleShuffle(); });
mappings.add([modes.PLAYER],
["r"], "Toggle repeat",
function () { player.toggleRepeat(); });
mappings.add([modes.PLAYER],
["h", "<Left>"], "Seek -10s",
function (count) { player.seekBackward(Math.max(1, count) * 10000); },
{ count: true });
mappings.add([modes.PLAYER],
["l", "<Right>"], "Seek +10s",
function (count) { player.seekForward(Math.max(1, count) * 10000); },
{ count: true });
mappings.add([modes.PLAYER],
["H", "<S-Left>"], "Seek -1m",
function (count) { player.seekBackward(Math.max(1, count) * 60000); },
{ count: true });
mappings.add([modes.PLAYER],
["L", "<S-Right>"], "Seek +1m",
function (count) { player.seekForward(Math.max(1, count) * 60000); },
{ count: true });
mappings.add([modes.PLAYER],
["=", "+"], "Increase volume by 5% of the maximum",
function () { player.increaseVolume(); });
mappings.add([modes.PLAYER],
["-"], "Decrease volume by 5% of the maximum",
function () { player.decreaseVolume(); });
mappings.add([modes.PLAYER],
["/"], "Search forward for a track",
function (args) { commandline.open("/", "", modes.SEARCH_VIEW_FORWARD); });
mappings.add([modes.PLAYER],
["n"], "Find the next track",
function () { player.searchViewAgain(false);});
mappings.add([modes.PLAYER],
["N"], "Find the previous track",
function () { player.searchViewAgain(true);});
for (let i in util.range(0, 6)) {
let (rating = i) {
mappings.add([modes.PLAYER],
["<C-" + rating + ">"], "Rate the current media item " + rating,
function () {
let item = gMM.sequencer.currentItem || this._currentView.selection.currentMediaItem; // XXX: a bit too magic
if (item)
player.rateMediaItem(item, rating);
else
dactyl.beep();
}
);
};
}
},
options: function () {
options.add(["repeat"],
"Set the playback repeat mode",
"number", 0,
{
setter: function (value) gMM.sequencer.repeatMode = value,
getter: function () gMM.sequencer.repeatMode,
completer: function (context) [
["0", "Repeat none"],
["1", "Repeat one"],
["2", "Repeat all"]
],
validator: Option.validateCompleter
});
options.add(["shuffle"],
"Play tracks in shuffled order",
"boolean", false,
{
setter: function (value) gMM.sequencer.mode = value ? gMM.sequencer.MODE_SHUFFLE : gMM.sequencer.MODE_FORWARD,
getter: function () gMM.sequencer.mode == gMM.sequencer.MODE_SHUFFLE
});
}
});
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="162"
height="40"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docbase="/home/maxauthority/code/pentadactyl"
sodipodi:docname="xulmus.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/maxauthority/code/pentadactyl/xulmus.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 29 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="185 : 29 : 1"
inkscape:persp3d-origin="92.5 : 19.333333 : 1"
id="perspective2392" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.04"
inkscape:cx="84.114858"
inkscape:cy="55.052209"
inkscape:document-units="px"
inkscape:current-layer="layer1"
width="185px"
height="58px"
showgrid="false" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-5.4392018,-9.6624603)">
<text
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono"
x="6.2673268"
y="29.896835"
id="text2229"><tspan
sodipodi:role="line"
id="tspan2231"
x="6.2673268"
y="29.896835">xulmus_</tspan></text>
<text
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono"
x="6.4079518"
y="53.183945"
id="text2233"><tspan
sodipodi:role="line"
id="tspan2235"
x="6.4079518"
y="53.183945">~</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,9 @@
VIMBALL = xulmus.vba
vimball: mkvimball.txt syntax/xulmus.vim ftdetect/xulmus.vim
-echo '%MkVimball! ${VIMBALL} .' | vim -u NORC -N -e -s mkvimball.txt
all: vimball
clean:
rm -f ${VIMBALL}

View File

@@ -0,0 +1,2 @@
" TODO: what's the Xulmus filename extension?
au BufNewFile,BufRead *xulmusrc*,*.xulmus set filetype=xulmus

View File

@@ -0,0 +1,2 @@
syntax/xulmus.vim
ftdetect/xulmus.vim

View File

@@ -0,0 +1,111 @@
" Vim syntax file
" Language: Xulmus configuration file
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Last Change: 2009 Nov 14
" TODO: make this xulmus specific - shared dactyl config?
if exists("b:current_syntax")
finish
endif
let s:cpo_save = &cpo
set cpo&vim
syn include @javascriptTop syntax/javascript.vim
unlet b:current_syntax
syn include @cssTop syntax/css.vim
unlet b:current_syntax
syn match xulmusCommandStart "\%(^\s*:\=\)\@<=" nextgroup=xulmusCommand,xulmusAutoCmd
syn keyword xulmusCommand ab[breviate] ab[clear] addo[ns] bN[ext] b[uffer] ba[ck] bd[elete] beep bf[irst] bl[ast] bma[rk] bmarks
\ bn[ext] bp[revious] br[ewind] bufd[o] buffers bun[load] bw[ipeout] ca[bbrev] cabc[lear] cd chd[ir] cm[ap] cmapc[lear]
\ cno[remap] colo[rscheme] com[mand] comc[lear] cu[nmap] cuna[bbrev] delbm[arks] delc[ommand] delm[arks] delmac[ros]
\ delqm[arks] dels[tyle] dia[log] displayp[ane] dl do[autocmd] doautoa[ll] downl[oads] dp[ane] dpcl[ose] dpope[n] ec[ho]
\ echoe[rr] echom[sg] em[enu] exe[cute] exta[dd] extd[isable] extde[lete] exte[nable] extens[ions] exto[ptions]
\ extp[references] exu[sage] f[ilter] files fini[sh] fo[rward] frameo[nly] fw h[elp] helpa[ll] ha[rdcopy] hi[ghlight]
\ hist[ory] hs ia[bbrev] iabc[lear] im[ap] imapc[lear] ino[remap] iu[nmap] iuna[bbrev] javas[cript] js ju[mps] let load
\ loadplugins lpl ls ma[rk] macros map mapc[lear] marks mediav[iew] mes[sages] messc[lear] mkv[imperatorrc] mkx[ulmusrc]
\ nm[ap] nmap[clear] nno[remap] no[remap] noh[lsearch] norm[al] nu[nmap] o[pen] optionu[sage] pa[geinfo] pagest[yle] pas
\ playern[ext] playerp[lay] playerpa[use] playerpr[ev] players[top] pm[ap] pmap[clear] pno[remap] pref[erences] prefs
\ pu[nmap] pw[d] q[uit] qa[ll] qma[rk] qmarks queue quita[ll] re[draw] re[load] reloada[ll] res[tart] run runt[ime] sav[eas]
\ sb[ar] sb[open] sbcl[ose] scrip[tnames] se[t] see[k] setg[lobal] setl[ocal] sideb[ar] sil[ent] sort[view] so[urce] st[op]
\ stopa[ll] sty[le] tN[ext] t[open] tab tabN[ext] tabc[lose] tabd[o] tabde[tach] tabdu[plicate] tabfir[st] tabl[ast] tabm[ove]
\ tabn[ext] tabnew tabo[nly] tabopen tabp[revious] tabr[ewind] tabs tbh[ide] tbs[how] tbt[oggle] time tn[ext] toolbarh[ide]
\ toolbars[how] toolbart[oggle] tp[revious] u[ndo] una[bbreviate] undoa[ll] unl[et] unm[ap] verb[ose] ve[rsion] vie[wsource]
\ viu[sage] vm[ap] vmap[clear] vno[remap] vol[ume] vu[nmap] w[rite] wc[lose] winc[lose] wq wqa[ll] xa[ll] zo[om]
\ contained
syn match xulmusCommand "!" contained
syn keyword xulmusAutoCmd au[tocmd] contained nextgroup=xulmusAutoEventList skipwhite
syn keyword xulmusAutoEvent BookmarkAdd ColorScheme DOMLoad DownloadPost Fullscreen LocationChange PageLoad PageLoadPre
\ ShellCmdPost StreamEnd StreamPause StreamStart StreamStop TrackChange TrackChangePre ViewChange ViewChangePre XulmusEnter
\ XulmusLeave XulmusLeavePre
\ contained
syn match xulmusAutoEventList "\(\a\+,\)*\a\+" contained contains=xulmusAutoEvent
syn region xulmusSet matchgroup=xulmusCommand start="\%(^\s*:\=\)\@<=\<\%(setl\%[ocal]\|setg\%[lobal]\|set\=\)\=\>"
\ end="$" keepend oneline contains=xulmusOption,xulmusString
syn keyword xulmusOption activate act cdpath cd complete cpt defsearch ds editor encoding enc eventignore ei extendedhinttags eht
\ fileencoding fenc followhints fh guioptions go helpfile hf hintinputs hin hintmatching hm hinttags ht hinttimeout hto
\ history hi laststatus ls maxitems messages msgs newtab nextpattern pageinfo pa popups pps previouspattern repeat runtimepath
\ rtp scroll scr shell sh shellcmdflag shcf showstatuslinks ssli showtabline stal suggestengines titlestring urlseparator
\ verbose vbs wildcase wic wildignore wig wildmode wim wildoptions wop wordseparators wsp
\ contained nextgroup=xulmusSetMod
" toggle options
syn match xulmusOption "\<\%(no\|inv\)\=\%(errorbells\|eb\|exrc\|ex\|focuscontent\|fc\|fullscreen\|fs\|ignorecase\|ic\)\>!\="
\ contained nextgroup=xulmusSetMod
syn match xulmusOption "\<\%(no\|inv\)\=\%(incsearch\|is\|insertmode\|im\|hlsearch\|hls\|linksearch\|lks\)\>!\="
\ contained nextgroup=xulmusSetMod
syn match xulmusOption "\<\%(no\|inv\)\=\%(loadplugins\|lpl\|more\|online\|shuffle\|showmode\|smd\|smartcase\|scs\)\>!\="
\ contained nextgroup=xulmusSetMod
syn match xulmusOption "\<\%(no\|inv\)\=\%(online\|visualbell\|vb\|usermode\|um\)\>!\="
\ contained nextgroup=xulmusSetMod
syn match xulmusSetMod "\%(\<[a-z_]\+\)\@<=&" contained
syn region xulmusJavaScript start="\%(^\s*\%(javascript\|js\)\s\+\)\@<=" end="$" contains=@javascriptTop keepend oneline
syn region xulmusJavaScript matchgroup=xulmusJavaScriptDelimiter
\ start="\%(^\s*\%(javascript\|js\)\s\+\)\@<=<<\s*\z(\h\w*\)"hs=s+2 end="^\z1$" contains=@javascriptTop fold
let s:cssRegionStart = '\%(^\s*sty\%[le]!\=\s\+\%(-\%(n\|name\)\%(\s\+\|=\)\S\+\s\+\)\=[^-]\S\+\s\+\)\@<='
execute 'syn region xulmusCss start="' . s:cssRegionStart . '" end="$" contains=@cssTop keepend oneline'
execute 'syn region xulmusCss matchgroup=xulmusCssDelimiter'
\ 'start="' . s:cssRegionStart . '<<\s*\z(\h\w*\)"hs=s+2 end="^\z1$" contains=@cssTop fold'
syn match xulmusNotation "<[0-9A-Za-z-]\+>"
syn match xulmusComment +".*$+ contains=xulmusTodo,@Spell
syn keyword xulmusTodo FIXME NOTE TODO XXX contained
syn region xulmusString start="\z(["']\)" end="\z1" skip="\\\\\|\\\z1" oneline
syn match xulmusLineComment +^\s*".*$+ contains=xulmusTodo,@Spell
" NOTE: match vim.vim highlighting group names
hi def link xulmusAutoCmd xulmusCommand
hi def link xulmusAutoEvent Type
hi def link xulmusCommand Statement
hi def link xulmusComment Comment
hi def link xulmusJavaScriptDelimiter Delimiter
hi def link xulmusCssDelimiter Delimiter
hi def link xulmusNotation Special
hi def link xulmusLineComment Comment
hi def link xulmusOption PreProc
hi def link xulmusSetMod xulmusOption
hi def link xulmusString String
hi def link xulmusTodo Todo
let b:current_syntax = "xulmus"
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: tw=130 et ts=4 sw=4:

View File

@@ -0,0 +1,4 @@
pref("extensions.dactyl.name", "melodactyl");
pref("extensions.dactyl.appName", "Melodactyl");
pref("extensions.dactyl.idName", "MELODACTYL");
pref("extensions.dactyl.host", "Songbird");

25
melodactyl/install.rdf Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#"
xmlns:songbird="http://www.songbirdnest.com/2007/addon-metadata-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>melodactyl@dactyl.googlecode.com</em:id>
<em:type>2</em:type>
<em:name>Melodactyl</em:name>
<em:version>0.1a1pre</em:version>
<em:description>Songbird for Vim and CMus junkies.</em:description>
<em:creator>Prathyush Thota</em:creator>
<em:homepageURL>http://dactyl.sourceforge.net/</em:homepageURL>
<em:iconURL>chrome://melodactyl/skin/icon.png</em:iconURL>
<em:optionsURL>chrome://dactyl/content/preferences.xul</em:optionsURL>
<em:targetApplication>
<Description>
<em:id>songbird@songbirdnest.com</em:id>
<em:minVersion>1.8.0</em:minVersion>
<em:maxVersion>1.9.0</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>
<!-- vim: set fdm=marker sw=4 ts=4 et: -->

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>
<!DOCTYPE overlay SYSTEM "chrome://dactyl/content/dactyl.dtd">
<overlay
xmlns="http://vimperator.org/namespaces/liberator"
xmlns:html="http://www.w3.org/1999/xhtml">
<include href="player" tag="player.html" insertafter="intro.html"/>
</overlay>
<!-- vim:se sts=4 sw=4 et: -->

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>
<!DOCTYPE overlay SYSTEM "chrome://dactyl/content/dactyl.dtd">
<overlay
xmlns="http://vimperator.org/namespaces/liberator"
xmlns:html="http://www.w3.org/1999/xhtml">
<dl tag="autocommand-list" replace="autocommand-list">
<dt>BookmarkAdd</dt> <dd>Triggered after a page is bookmarked</dd>
<dt>ColorScheme</dt> <dd>Triggered after a color scheme has been loaded</dd>
<dt>DOMLoad</dt> <dd>Triggered when a page's DOM content has fully loaded</dd>
<dt>DownloadPost</dt> <dd>Triggered when a download has completed</dd>
<dt>Fullscreen</dt> <dd>Triggered when the player's fullscreen state changes</dd>
<dt>LocationChange</dt><dd>Triggered when changing tabs or when navigating to a new location</dd>
<dt>PageLoadPre</dt> <dd>Triggered after a page load is initiated</dd>
<dt>PageLoad</dt> <dd>Triggered when a page gets (re)loaded/opened</dd>
<dt>ShellCmdPost</dt> <dd>Triggered after executing a shell command with <ex>:!</ex>#{cmd}</dd>
<dt>TrackChangePre</dt><dd>Triggered before a playing track is changed</dd>
<dt>TrackChange</dt> <dd>Triggered after a playing track has changed</dd>
<dt>ViewChangePre</dt> <dd>Triggered before a sequencer view is changed</dd>
<dt>ViewChange</dt> <dd>Triggered after a sequencer view is changed</dd>
<dt>StreamStart</dt> <dd>Triggered after a stream has started</dd>
<dt>StreamPause</dt> <dd>Triggered after a stream has paused</dd>
<dt>StreamEnd</dt> <dd>Triggered after a stream has ended</dd>
<dt>StreamStop</dt> <dd>Triggered after a stream has stopped</dd>
<dt>XulmusEnter</dt> <dd>Triggered after Songbird starts</dd>
<dt>XulmusLeavePre</dt><dd>Triggered before exiting Songbird, just before destroying each module</dd>
<dt>XulmusLeave</dt> <dd>Triggered before exiting Songbird</dd>
</dl>
<dl tag="autocommand-args" replace="autocommand-args">
<dt>&lt;url></dt> <dd>The URL against which the event was selected.</dd>
<dt>&lt;title></dt> <dd>The page, bookmark or download title.</dd>
<dt>&lt;doc></dt> <dd>The document for which the event occurred. Only for <em>DOMLoad</em>, <em>PageLoad</em> and <em>PageLoadPre</em>.</dd>
<dt>&lt;tab></dt> <dd>The tab in which the event occurred. Only for <em>DOMLoad</em>, <em>PageLoad</em> and <em>PageLoadPre</em>.</dd>
<dt>&lt;tags></dt> <dd>The tags applied to &lt;url>. Only for <em>BookmarkAdd</em>.</dd>
<dt>&lt;keyword></dt><dd>The keywords applied to the bookmark. Only for <em>BookmarkAdd</em>.</dd>
<dt>&lt;icon></dt> <dd>The icon associated with &lt;url>. Only for <em>BookmarkAdd</em>.</dd>
<dt>&lt;size></dt> <dd>The size of a downloaded file. Only for <em>DownloadPost</em>.</dd>
<dt>&lt;file></dt> <dd>The target destination of a download. Only for <em>DownloadPost</em>.</dd>
<dt>&lt;state></dt> <dd>The new fullscreen state. Only for <em>Fullscreen</em>.</dd>
<dt>&lt;name></dt> <dd>The color scheme name. Only for <em>ColorScheme</em>.</dd>
<dt>&lt;view></dt> <dd>The new sequencer view. Only for <em>ViewChangePre</em> and <em>ViewChange</em>.</dd>
<dt>&lt;track></dt> <dd>The new media track. Only for <em>TrackChangePre</em>, <em>TrackChange</em> and <em>Stream</em>.</dd>
</dl>
</overlay>
<!-- vim:se sts=4 sw=4 et: -->

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>
<!DOCTYPE overlay SYSTEM "chrome://dactyl/content/dactyl.dtd">
<overlay
xmlns="http://vimperator.org/namespaces/liberator"
xmlns:html="http://www.w3.org/1999/xhtml">
<span replace="w"/>
<span replace="W"/>
<span replace=":wc"/>
<span replace=":winon"/>
</overlay>
<!-- vim:se sts=4 sw=4 et: -->

View File

@@ -0,0 +1,4 @@
<!ENTITY appName "Xulmus">
<!ENTITY hostapp "Songbird">

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>
<!DOCTYPE overlay SYSTEM "chrome://dactyl/content/dactyl.dtd">
<overlay
xmlns="http://vimperator.org/namespaces/liberator"
xmlns:html="http://www.w3.org/1999/xhtml">
<dl tag="dialog-list" replace="dialog-list">
<dt>about</dt> <dd>About &dactyl.host;</dd>
<dt>addons</dt> <dd>Manage Add-ons</dd>
<dt>checkupdates</dt> <dd>Check for updates</dd>
<dt>cleardata</dt> <dd>Clear private data</dd>
<dt>cookies</dt> <dd>List your cookies</dd>
<dt>console</dt> <dd>JavaScript console</dd>
<dt>dominspector</dt> <dd>DOM Inspector</dd>
<dt>downloads</dt> <dd>Manage Downloads</dd>
<dt>jumpto</dt> <dd>Jump to a media item</dd>
<dt>newsmartplaylist</dt><dd>Create a new smart playlist</dd>
<dt>openfile</dt> <dd>Open the file selector dialog</dd>
<dt>pagesource</dt> <dd>View page source</dd>
<dt>places</dt> <dd>Places Organizer: Manage your bookmarks and history</dd>
<dt>preferences</dt> <dd>Show &dactyl.host; preferences dialog</dd>
<dt>printsetup</dt> <dd>Setup the page size and orientation before printing</dd>
<dt>print</dt> <dd>Show print dialog</dd>
<dt>saveframe</dt> <dd>Save frame to disk</dd>
<dt>savepage</dt> <dd>Save page to disk</dd>
<dt>searchengines</dt> <dd>Manage installed search engines</dd>
<dt>selectionsource</dt> <dd>View selection source</dd>
<dt>subscribe</dt> <dd>Add a new subscription</dd>
</dl>
<item replace="sbcl">
<tags>:dpcl :dpclose</tags>
<spec>:dpcl<oa>ose</oa> <a>pane</a></spec>
<description>
<p>Close the specified display pane.</p>
</description>
</item>
<item replace=":sbope">
<tags>:dpope :dpopen :dp :dpane :dislplayp :dislplaypane</tags>
<spec>:displaypane <a>pane</a></spec>
<description>
<p>
Open the specified display pane. <a>pane</a> is any of "service
pane left", "service pane bottom", "content pane bottom" or "right
sidebar".
</p>
</description>
</item>
</overlay>
<!-- vim:se sts=4 sw=4 et: -->

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>
<!DOCTYPE document SYSTEM "chrome://dactyl/content/dactyl.dtd">
<document
name="intro"
title="&dactyl.appName; Intro"
xmlns="http://vimperator.org/namespaces/liberator"
xmlns:html="http://www.w3.org/1999/xhtml">
<logo/>
<h2 tag="intro">Introduction</h2>
<link topic="http://vimperator.org/%dactyl.name;">&dactyl.appName;</link>
is a free media player add-on for &dactyl.host;, which
combines the best features of the
<link topic="http://cmus.sourceforge.net">CMus</link>
music player and the
<link topic="http://www.vim.org">Vim</link>
text editor.
<warning tag="warning">
To provide the most authentic CMus/Vim experience, the &dactyl.host; toolbar
is hidden.
If you really need it, type: <ex>:set guioptions+=T</ex> to get it back.
If you don't like &dactyl.appName; at all, you can uninstall it by typing
<ex>:extdelete &dactyl.appName;</ex> or <ex>:extdisable &dactyl.appName;</ex> to disable it.
If you like it but can't remember the shortcuts, then press <k>F1</k> or
<ex>:help</ex> to get this help window back.
</warning>
<tags>author donation</tags>
<p>
&dactyl.appName; was written by
<link topic="prathyushthota@gmail.com">Prathyush Thota</link>. If you
appreciate my work on &dactyl.appName; and want to encourage
me working on it more, you can either send me greetings, patches
or make a donation:
</p>
<pan><handle/></pan>
<p>
Of course as a believer in free open source software, only make
a donation if you really like &dactyl.appName; and the money
doesn't hurt -- otherwise just use it, recommend it and like it
:)
</p>
<h2 tag="overview">Help topics</h2>
<ul>
<li><link topic="starting">Starting &dactyl.appName;</link>: How &dactyl.appName; starts up, where it reads the config file... </li>
<li><link topic="player">Player mode</link>: Interacting with the media player.</li>
<li><link topic="browsing">Browsing</link>: Basic mappings and commands needed for a browsing session (how to open a web page or go back in history).</li>
<li><link topic="buffer">Buffer</link>: Operations on the current document like scrolling or copying text.</li>
<li><link topic="cmdline">Command-line mode</link>: Command-line editing.</li>
<li><link topic="insert">Insert mode</link>: Insert-mode editing.</li>
<li><link topic="options">Options</link>: A description of all options.</li>
<li><link topic="pattern">Text search commands</link>: Searching for text in the current buffer.</li>
<li><link topic="tabs">Tabs</link>: Managing your tabbed browsing session.</li>
<li><link topic="hints">Hints</link>: Selecting hyperlinks and other page elements.</li>
<li><link topic="map">Key mappings, abbreviations, and user-defined commands</link>: Defining new key mappings, abbreviations and user commands.</li>
<li><link topic="eval">Expression evaluation</link>: Executing JavaScript.</li>
<li><link topic="marks">Marks</link>: Using bookmarks, QuickMarks, history and local marks.</li>
<li><link topic="repeat">Repeating commands</link>: Using macros to repeat recurring workflows.</li>
<li><link topic="autocommands">Automatic commands</link>: Automatically executing code on certain events.</li>
<li><link topic="print">Printing</link>: Printing pages.</li>
<li><link topic="gui">&dactyl.appName;'s GUI</link>: Accessing &dactyl.host; menus, dialogs and the display panels.</li>
<li><link topic="styling">Styling the GUI and web pages</link>: Changing the styling of content pages and &dactyl.appName; itself.</li>
<li><link topic="message">Error and informational messages</link>: A description of messages and error messages.</li>
<li><link topic="developer">Developer information</link>: How to write docs or plugins.</li>
<li><link topic="various">Various commands</link>: Other help which didn't fit into any other category.</li>
<li><link topic="index">Index</link>: An index of all commands and options.</li>
</ul>
<p>
You can also jump directly to the help of a specific command
with <ex>:help o</ex> or <ex>:help :set</ex>.
</p>
<h2 tag="features">Features</h2>
<!-- TODO: make Xulmus specific -->
<ul>
<li>Vim-like keybindings (<k>h</k>, <k>j</k>, <k>k</k>, <k>l</k>, <k>gg</k>, <k>G</k>, <k>0</k>, <k>$</k>, <k>ZZ</k>, <k name="C-f"/>, etc.)</li>
<li>Ex commands (<ex>:quit</ex>, <ex>:open www.foo.com</ex>, ...)</li>
<li>Tab completion available for all commands with support for "longest" matching when set in 'wildmode'</li>
<li>Hit-a-hint like navigation of links (start with <k>f</k> to follow a link)</li>
<li>Advanced completion of bookmark and history URLs (searching also in title, not only URL)</li>
<li>Vim-like statusline with a Wget-like progress bar</li>
<li>Minimal GUI (easily hide useless menubar and toolbar with <ex>:set guioptions=</ex>)</li>
<li>Ability to <ex>:source</ex> JavaScript files, and to use a [a]~/.xulmusrc[a] file with syntax highlighting if you install http://code.google.com/p/pentadactyl-labs/issues/detail?id=50[xulmus.vim]</li>
<li>Easy quick searches (<ex>:open foo</ex> will search for "foo" in google, <ex>:open ebay terminator</ex> will search for "terminator" on ebay) with support for &dactyl.host; keyword bookmarks and search engines</li>
<li>Count supported for many commands (<em>3</em><k name="C-o"/> will go back 3 pages)</li>
<li>Beep on errors</li>
<li>Marks support (<k>m</k><em>a</em> to set mark a on a web page, <k>'</k><em>a</em> to go there)</li>
<li>QuickMarks support (quickly go to previously marked web pages with <k>go</k><a>a-zA-Z0-9</a>)</li>
<li><ex>:map</ex> and <ex>:command</ex> support (and feedkeys() for script writers)</li>
<li><ex>:time</ex> support for profiling</li>
<li>Move the text cursor and select text with Vim keys and a Visual mode</li>
<li>External editor support</li>
<li>Macros to replay key strokes</li>
<li>AutoCommands to execute actions on certain events</li>
<li>A comprehensive help system, explaining all commands, mappings and options</li>
</ul>
<h2 tag="contact">Contact</h2>
<p>
Please send comments/bug reports/patches to the mailing list,
where we will properly answer any questions. You can also join
the
<link topic="irc://irc.oftc.net/pentadactyl">#pentadactyl</link>
IRC channel on
<link topic="http://www.oftc.net/">OFTC</link> or check the
<link topic="http://code.google.com/p/dactyl/w/list?q=label%3Aproject-&dactyl.name;">Wiki</link>
for
<link topic="http://code.google.com/p/dactyl/wiki/FAQ">
frequently asked questions (FAQ)</link>.
Make sure, you have read the
<link topic="http://dactyl.googlecode.com/hg/xulmus/TODO">TODO</link>
file first, as we are aware of many things which can be improved
when we find time for it or receive patches.
</p>
</document>
<!-- vim:se sts=4 sw=4 et: -->

View File

@@ -0,0 +1,327 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>
<!DOCTYPE document SYSTEM "chrome://dactyl/content/dactyl.dtd">
<document
name="browsing"
title="&dactyl.appName; Browsing"
xmlns="http://vimperator.org/namespaces/liberator"
xmlns:html="http://www.w3.org/1999/xhtml">
<h1 tag="player-mode player">Player mode</h1>
<toc start="2"/>
<p>
The following features apply to Player mode which is activated when the
media tab has focus.
</p>
<h2 tag="playing-tracks">Playing tracks</h2>
<item>
<tags>p_x :playerp :playerplay</tags>
<spec>:playerp<oa>lay</oa></spec>
<spec>x</spec>
<description>
<p>
Play the current track.
</p>
</description>
</item>
<item>
<tags>p_z :playerpr :playerprev</tags>
<spec>:playerpr<oa>ev</oa></spec>
<spec>z</spec>
<description>
<p>
Play the previous track.
</p>
</description>
</item>
<item>
<tags>p_b :playern :playernext</tags>
<spec>:playern<oa>ext</oa></spec>
<spec>b</spec>
<description>
<p>
Play the next track.
</p>
</description>
</item>
<item>
<tags>p_c :playerpa :playerpause</tags>
<spec>:playerpa<oa>use</oa></spec>
<spec>c</spec>
<description>
<p>
Pause/unpause the current track.
</p>
</description>
</item>
<item>
<tags>p_v :playerps :playerstop</tags>
<spec>:playerps<oa>top</oa></spec>
<spec>v</spec>
<description>
<p>
Stop playing the current track.
</p>
</description>
</item>
<item>
<tags>p_x</tags>
<spec>x</spec>
<description>
<p>
Toggle shuffle mode.
</p>
</description>
</item>
<item>
<tags>p_r</tags>
<spec>r</spec>
<description>
<p>
Toggle repeat mode.
</p>
</description>
</item>
<item>
<tags>p_i</tags>
<spec>i</spec>
<description>
<p>
Select the currently playing track.
</p>
</description>
</item>
<h2 tag="queue queueing">Queueing tracks</h2>
<item>
<tags>p_Q :qu :queue</tags>
<spec>:qu<oa>eue</oa> <a>artist</a> <oa>album</oa> <oa>track</oa></spec>
<spec>Q</spec>
<description>
<p>
Queue tracks by artist/album/track. If only <a>artist</a> is
specified then all tracks for that artist are played in album
order. If <oa>album</oa> is also specified then all tracks for that
album are played. A specific track can be specified with
<oa>track</oa>.
</p>
</description>
</item>
<h2 tag="filter filtering">Filtering the library</h2>
<item>
<tags>p_f :f :filter</tags>
<spec>:f<oa>ilter</oa> <a>keywords</a></spec>
<spec>f</spec>
<description>
<p>
Filter and show the tracks as a view. The tracks are filtered by
the <a>keywords</a> provided as arguments. This text search applies
over the default filter properties, namely: Genre, Artist, Album
and Track.
</p>
</description>
</item>
<h2 tag="seeking">Seeking to a track position</h2>
<item>
<tags><![CDATA[p_<Left> p_h]]></tags>
<spec><oa>count</oa>h</spec>
<description>
<p>
Seek +10s.
</p>
</description>
</item>
<item>
<tags><![CDATA[p_<Right> p_l]]></tags>
<spec><oa>count</oa>l</spec>
<description>
<p>
Seek -10s.
</p>
</description>
</item>
<item>
<tags><![CDATA[p_<S-Left> p_H]]></tags>
<spec><oa>count</oa>H</spec>
<description>
<p>
Seek +1m.
</p>
</description>
</item>
<item>
<tags><![CDATA[p_<S-Right> p_L]]></tags>
<spec><oa>count</oa>L</spec>
<description>
<p>
Seek -1m.
</p>
</description>
</item>
<item>
<tags>:see :seek</tags>
<spec>:see<oa>k</oa> <a>[HH:]MM:SS]</a></spec>
<spec>:see<oa>k</oa> +<a>time[hms]</a> | -<a>time[hms]</a></spec>
<description>
<p>
Seek to an absolute or relative position in a track. The position
can be given in seconds (s), minutes (m), or hours (h). If the unit
is not specified then seconds is assumed. The position is absolute
unless the value is prefixed with "-" or "+".
</p>
<p>
Positions may also be specified in <a>[HH:]MM:SS</a> format.
</p>
</description>
</item>
<h2 tag="volume">Adjusting the volume</h2>
<item>
<tags>p_+ p_=</tags>
<spec>+</spec>
<spec>=</spec>
<description>
<p>
Increase volume by 5% of the maximum.
</p>
</description>
</item>
<item>
<tags>p_-</tags>
<spec>-</spec>
<description>
<p>
Decrease volume by 5% of the maximum.
</p>
</description>
</item>
<item>
<tags>:vol :volume</tags>
<spec>vol<oa>[ume]</oa> <a>value</a></spec>
<spec>vol<oa>[ume]</oa> +<a>value</a> | -<a>value</a></spec>
<description>
<p>
Set the player volume. <a>value</a> can be an absolute value
between 0 and 100% or a relative value if prefixed with "-" or "+".
</p>
</description>
</item>
<h2 tag="playlists">Managing playlists</h2>
<item>
<tags>:load</tags>
<spec>:load <oa>playlist</oa></spec>
<description>
<p>
Load <a>playlist</a>. If no playlist is specified then the main
library view is loaded.
</p>
</description>
</item>
<h2 tag="media-view view">Changing media views</h2>
<item>
<tags>:mediav :mediaview</tags>
<spec>:mediav<oa>ew</oa> <a>view</a></spec>
<description>
<p>
Change the media view to <a>view</a>. This can only be run when the
media tab is the current tab.
</p>
</description>
</item>
<h2 tag="search">Search commands</h2>
<item>
<tags>p_/</tags>
<spec>/<a>pattern</a></spec>
<description>
<p>
Search forward for a track matching <a>pattern</a> in the visible
media view.
</p>
</description>
</item>
<!--
<item>
<tags>p_?</tags>
<spec>?<a>pattern</a></spec>
<description>
<p>
Search backwards for a track matching <a>pattern</a> in the visible
media view.
</p>
</description>
</item>
-->
<item>
<tags>p_n</tags>
<spec>n</spec>
<description>
<p>
Find the next track. Repeats the last search. If the search hits
BOTTOM of the view, it continues from TOP.
</p>
</description>
</item>
<item>
<tags>p_N</tags>
<spec>N</spec>
<description>
<p>
Find the previous track. Repeats the last search in the opposite
direction. If the search hits TOP of the view, it continues from
BOTTTOM.
</p>
</description>
</item>
<h2 tag="rating">Rating tracks</h2>
<item>
<tags><![CDATA[p_<C-5> p_<C-4> p_<C-3> p_<C-2> p_<C-1> p_<C-0>]]></tags>
<spec><![CDATA[<C-0>]]></spec>
<spec><![CDATA[<C-1>]]></spec>
<spec><![CDATA[<C-2>]]></spec>
<spec><![CDATA[<C-3>]]></spec>
<spec><![CDATA[<C-4>]]></spec>
<spec><![CDATA[<C-5>]]></spec>
<description>
<p>
Rate the current track with N stars.
</p>
</description>
</item>
</document>
<!-- vim:se sts=4 sw=4 et: -->

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="chrome://dactyl/content/help.xsl"?>
<!DOCTYPE overlay SYSTEM "chrome://dactyl/content/dactyl.dtd">
<overlay
xmlns="http://vimperator.org/namespaces/liberator"
xmlns:html="http://www.w3.org/1999/xhtml">
<span replace=":window"/>
<span replace=":u"/>
<span replace=":undoa"/>
</overlay>
<!-- vim:se sts=4 sw=4 et: -->

BIN
melodactyl/skin/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B