Skip to content
This repository has been archived by the owner on Jun 20, 2018. It is now read-only.

Commit

Permalink
Add window state API (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
mmorhun authored and benoitf committed Jun 19, 2018
1 parent a3f110f commit 9e22b57
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 8 deletions.
7 changes: 6 additions & 1 deletion packages/plugin-ext/src/api/plugin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export interface QuickOpenMain {
$input(options: theia.InputBoxOptions, validateInput: boolean): PromiseLike<string>;
}

export interface WindowStateExt {
$onWindowStateChanged(focus: boolean): void;
}

export const PLUGIN_RPC_CONTEXT = {
COMMAND_REGISTRY_MAIN: <ProxyIdentifier<CommandRegistryMain>>createProxyIdentifier<CommandRegistryMain>('CommandRegistryMain'),
QUICK_OPEN_MAIN: createProxyIdentifier<QuickOpenMain>('QuickOpenMain'),
Expand All @@ -89,5 +93,6 @@ export const PLUGIN_RPC_CONTEXT = {
export const MAIN_RPC_CONTEXT = {
HOSTED_PLUGIN_MANAGER_EXT: createProxyIdentifier<HostedPluginManagerExt>('HostedPluginManagerExt'),
COMMAND_REGISTRY_EXT: createProxyIdentifier<CommandRegistryExt>('CommandRegistryExt'),
QUICK_OPEN_EXT: createProxyIdentifier<QuickOpenExt>('QuickOpenExt')
QUICK_OPEN_EXT: createProxyIdentifier<QuickOpenExt>('QuickOpenExt'),
WINDOW_STATE_EXT: createProxyIdentifier<WindowStateExt>('WindowStateExt')
};
5 changes: 5 additions & 0 deletions packages/plugin-ext/src/main/browser/main-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { QuickOpenMainImpl } from './quick-open-main';
import { RPCProtocol } from '../../api/rpc-protocol';
import { PLUGIN_RPC_CONTEXT } from '../../api/plugin-api';
import { MessageRegistryMainImpl } from './message-registry-main';
import { WindowStateMain } from './window-state-main';

export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container): void {
const commandRegistryMain = new CommandRegistryMainImpl(rpc, container);
Expand All @@ -20,4 +21,8 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container

const messageRegistryMain = new MessageRegistryMainImpl(container);
rpc.set(PLUGIN_RPC_CONTEXT.MESSAGE_REGISTRY_MAIN, messageRegistryMain);

// tslint:disable-next-line:no-unused-variable
// @ts-ignore
const windowStateMain = new WindowStateMain(rpc);
}
5 changes: 4 additions & 1 deletion packages/plugin-ext/src/main/browser/plugin-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ export class PluginWorker {
this.worker.onmessage = (message) => {
emmitter.fire(message.data);
};
this.worker.onerror = e => console.error(e);

this.rpc = new RPCProtocolImpl({
onMessage: emmitter.event,
send: (m: {}) => this.worker.postMessage(m)
send: (m: {}) => {
this.worker.postMessage(m);
}
});

}
Expand Down
26 changes: 26 additions & 0 deletions packages/plugin-ext/src/main/browser/window-state-main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2018 Red Hat, Inc. and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { WindowStateExt, MAIN_RPC_CONTEXT } from "../../api/plugin-api";
import { RPCProtocol } from "../../api/rpc-protocol";

export class WindowStateMain {

private proxy: WindowStateExt;

constructor(rpc: RPCProtocol) {
this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.WINDOW_STATE_EXT);

window.addEventListener("focus", () => this.onFocusChanged(true));
window.addEventListener("blur", () => this.onFocusChanged(false));
}

private onFocusChanged(focused: boolean): void {
this.proxy.$onWindowStateChanged(focused);
}

}
9 changes: 9 additions & 0 deletions packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import { RPCProtocol } from '../api/rpc-protocol';
import { getPluginId } from '../common/plugin-protocol';
import { Disposable } from './types-impl';
import { MessageRegistryExt } from './message-registry';
import { WindowStateExtImpl } from './window-state';

export function createAPI(rpc: RPCProtocol): typeof theia {
const commandRegistryExt = rpc.set(MAIN_RPC_CONTEXT.COMMAND_REGISTRY_EXT, new CommandRegistryImpl(rpc));
const quickOpenExt = rpc.set(MAIN_RPC_CONTEXT.QUICK_OPEN_EXT, new QuickOpenExtImpl(rpc));
const messageRegistryExt = new MessageRegistryExt(rpc);
const windowStateExt = rpc.set(MAIN_RPC_CONTEXT.WINDOW_STATE_EXT, new WindowStateExtImpl(rpc));

const commands: typeof theia.commands = {
registerCommand(command: theia.Command, handler?: <T>(...args: any[]) => T | Thenable<T>): Disposable {
Expand Down Expand Up @@ -53,6 +55,13 @@ export function createAPI(rpc: RPCProtocol): typeof theia {
optionsOrFirstItem: theia.MessageOptions | string | theia.MessageItem,
...items: any[]): PromiseLike<any> {
return messageRegistryExt.showErrorMessage(message, optionsOrFirstItem, items);
},

get state(): theia.WindowState {
return windowStateExt.getWindowState();
},
onDidChangeWindowState(listener, thisArg?, disposables?): theia.Disposable {
return windowStateExt.onDidChangeWindowState(listener, thisArg, disposables);
}
};

Expand Down
38 changes: 38 additions & 0 deletions packages/plugin-ext/src/plugin/window-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 Red Hat, Inc. and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { WindowState } from "@theia/plugin";
import { WindowStateExt } from "../api/plugin-api";
import { RPCProtocol } from "../api/rpc-protocol";
import { Event, Emitter } from "@theia/core/lib/common/event";

export class WindowStateExtImpl implements WindowStateExt {

private windowStateCached: WindowState;

private windowStateChangedEmitter = new Emitter<WindowState>();
public readonly onDidChangeWindowState: Event<WindowState> = this.windowStateChangedEmitter.event;

constructor(rpc: RPCProtocol) {
this.windowStateCached = { focused: true }; // supposed tab is active on start
}

getWindowState(): WindowState {
return this.windowStateCached;
}

$onWindowStateChanged(focused: boolean): void {
const state = { focused: focused };
if (state === this.windowStateCached) {
return;
}

this.windowStateCached = state;
this.windowStateChangedEmitter.fire(state);
}

}
40 changes: 34 additions & 6 deletions packages/plugin/API.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
# Introduction

## Theia Plugin system description

### Command API

A command is a unique identifier of a function which
can be executed by a user via a keyboard shortcut, a
menu action or directly.

Commands can be added using the [registerCommand](#commands.registerCommand) and
[registerTextEditorCommand](#commands.registerTextEditorCommand) functions.
Registration can be split in two step: first register command without handler,
second register handler by command id.
Registration can be split in two step: first register command without handler, second register handler by command id.

Any contributed command are available to any plugin, command can be invoked
by [executeCommand](#commands.executeCommand) function.
Any contributed command are available to any plugin, command can be invoked by [executeCommand](#commands.executeCommand) function.

Simple example that register command:

```javascript
theia.commands.registerCommand({id:'say.hello.command'}, ()=>{
console.log("Hello World!");
Expand Down Expand Up @@ -51,22 +52,49 @@ theia.window.showQuickPick(["foo", "bar", "foobar"], option).then((val: string[]
console.log(`Quick Pick Selected: ${val}`);
});
```

#### Notification API

A notification shows an information message to users.
Optionally provide an array of items which will be presented as clickable buttons.

Notifications can be shown using the [showInformationMessage](#window.showInformationMessage),
[showWarningMessage](#window.showWarningMessage) and [showErrorMessage](#window.showErrorMessage) functions.


Simple example that show an information message:

```javascript
theia.window.showInformationMessage('Information message');
```

Simple example that show an information message with buttons:

```javascript
theia.window.showInformationMessage('Information message', 'Btn1', 'Btn2').then(result => {
console.log("Click button", result);
});
```

#### Window State API

It is possible to track state of the IDE window inside a plugin. Window state is defined as:

```javascript
interface WindowState {
readonly focused: boolean;
}
```

To read a state on demand one can use readonly variable:

```javascript
theia.window.state
```

To track window activity subscribe on `onDidChangeWindowState` event:

```javascript
const disposable = theia.window.onDidChangeWindowState((windowState: theia.WindowState) => {
console.log('Window focus changed: ', windowState.focused);
});
```
23 changes: 23 additions & 0 deletions packages/plugin/src/theia.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ declare module '@theia/plugin' {
modal?: boolean;
}

/**
* Represents the state of a window.
*/
export interface WindowState {
/**
* Whether the current window is focused.
*/
readonly focused: boolean;
}

/**
* Common namespace for dealing with window and editor, showing messages and user input.
*/
Expand Down Expand Up @@ -416,5 +426,18 @@ declare module '@theia/plugin' {
* @return A promise that resolves to the selected item or `undefined` when being dismissed.
*/
export function showErrorMessage<T extends MessageItem>(message: string, options: MessageOptions, ...items: T[]): PromiseLike<T | undefined>;

/**
* Represents the current window's state.
*
* @readonly
*/
export let state: WindowState;

/**
* An event which fires when the focus state of the current window changes.
* The value of the event represents whether the window is focused.
*/
export const onDidChangeWindowState: Event<WindowState>;
}
}

0 comments on commit 9e22b57

Please sign in to comment.