Archived
Private
Public Access
1
0

Implemented Backend WindowAPI

This commit is contained in:
2022-11-05 12:19:14 +01:00
parent dd1d6dc89e
commit 46afa9cb7a
17 changed files with 305 additions and 416 deletions

View File

@@ -20,7 +20,7 @@
"@angular/router": "~13.1.0",
"rxjs": "~7.4.0",
"tslib": "^2.3.0",
"webdesktop_windowapi": "^1.0.4",
"webdesktop_windowapi": "^1.0.9",
"zone.js": "~0.11.4"
},
"devDependencies": {
@@ -11129,24 +11129,9 @@
}
},
"node_modules/webdesktop_windowapi": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/webdesktop_windowapi/-/webdesktop_windowapi-1.0.4.tgz",
"integrity": "sha512-UmL3DsTz2Tct0EI4llDOT5cn76wRCq9HJPL92EwQQykscv/4N0PXucdVf3eRLfxg7jtWNTDajW/taCx1l6zbCg==",
"dependencies": {
"typescript": "^4.8.4"
}
},
"node_modules/webdesktop_windowapi/node_modules/typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/webdesktop_windowapi/-/webdesktop_windowapi-1.0.9.tgz",
"integrity": "sha512-q84Auqs9HCjIi1T+Ny8sdCXQq00b4JZqVpiAhMS5vKpQmOMDtkarsgUgSiU0VRhtnAKojXsDENsqNtCXTYbhGw=="
},
"node_modules/webpack": {
"version": "5.65.0",
@@ -19728,19 +19713,9 @@
}
},
"webdesktop_windowapi": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/webdesktop_windowapi/-/webdesktop_windowapi-1.0.4.tgz",
"integrity": "sha512-UmL3DsTz2Tct0EI4llDOT5cn76wRCq9HJPL92EwQQykscv/4N0PXucdVf3eRLfxg7jtWNTDajW/taCx1l6zbCg==",
"requires": {
"typescript": "^4.8.4"
},
"dependencies": {
"typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ=="
}
}
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/webdesktop_windowapi/-/webdesktop_windowapi-1.0.9.tgz",
"integrity": "sha512-q84Auqs9HCjIi1T+Ny8sdCXQq00b4JZqVpiAhMS5vKpQmOMDtkarsgUgSiU0VRhtnAKojXsDENsqNtCXTYbhGw=="
},
"webpack": {
"version": "5.65.0",

View File

@@ -22,7 +22,7 @@
"@angular/router": "~13.1.0",
"rxjs": "~7.4.0",
"tslib": "^2.3.0",
"webdesktop_windowapi": "^1.0.4",
"webdesktop_windowapi": "^1.0.9",
"zone.js": "~0.11.4"
},
"devDependencies": {

View File

@@ -13,7 +13,7 @@
<div class="header-button">
<mat-icon class="minimize" (click)="toggleMinimized()">minimize</mat-icon>
</div>
<div class="header-button">
<div class="header-button" *ngIf="resizable">
<mat-icon (click)="toggleMaximized()">{{resizeIcon}}</mat-icon>
</div>
<div class="header-button">

View File

@@ -1,6 +1,8 @@
import {Component, ElementRef, ViewChild} from '@angular/core';
import {DesktopComponent, ProgramArgs} from "../../sites/desktop/desktop.component";
import {TaskbarIcon} from "../../sites/desktop/taskbar-icon/taskbar-icon.component";
import {Package} from "webdesktop_windowapi/dist/helper/Package";
import {WindowEvent} from "webdesktop_windowapi/dist/helper/EventData";
@Component({
selector: 'app-window-wrapper',
@@ -18,17 +20,26 @@ export class WindowWrapper {
public title: string;
public focused: boolean;
public contentLoaded: boolean = false;
public draggable: boolean = true;
public resizable: boolean = true;
public asPopup: boolean;
public args: string[];
public resizeIcon: string = "fullscreen";
public maximized: boolean = false;
private lastPos: { left: string, top: string, width: string, height: string };
private readonly messageHandler: (event: MessageEvent) => void;
constructor(private object: ElementRef) {
this.uuid = DesktopComponent.instance.generateWindowUUID();
this.messageHandler = this.onMessage.bind(this);
window.addEventListener('message', this.messageHandler);
}
public initialize(taskbar: TaskbarIcon) {
public initialize(taskbar: TaskbarIcon, args: string[], asPopup: boolean) {
this.title = this.program.name;
this.args = args;
this.asPopup = asPopup;
this.dragHandler = new DragHandler(this.wrapper.nativeElement, this);
this.resizeHandler = new ResizeHandler(this.wrapper.nativeElement, this);
this.taskbar = taskbar;
@@ -37,6 +48,8 @@ export class WindowWrapper {
}
public close() {
this.dispatchEvent({type: "close", data: undefined});
window.removeEventListener('message', this.messageHandler);
this.object.nativeElement.parentElement.removeChild(this.object.nativeElement);
this.taskbar.onClose(this);
}
@@ -104,12 +117,21 @@ export class WindowWrapper {
this.focused = false;
}
public receiveMessageFromWindow(sender: WindowWrapper, data: any) {
console.log(sender, data);
}
public applyContentListeners(content: HTMLIFrameElement) {
content.contentDocument.addEventListener('mousemove', this.onMove.bind(this));
content.contentDocument.addEventListener('mousedown', this.focus.bind(this));
content.contentDocument.addEventListener('mouseup', this.resizeHandler?.windowResizeStop.bind(this.resizeHandler));
/*content.contentWindow.addEventListener('mousemove', this.onMove.bind(this));
content.contentWindow.addEventListener('mousedown', this.focus.bind(this));
content.contentWindow.addEventListener('mouseup', this.resizeHandler?.windowResizeStop.bind(this.resizeHandler));*/
this.contentLoaded = true;
if (this.asPopup)
this.dispatchEvent({type: "openAsPopup", data: this.args});
else
this.dispatchEvent({type: "open", data: this.args});
}
public onMove(event: MouseEvent) {
@@ -117,6 +139,140 @@ export class WindowWrapper {
this.resizeHandler?.windowResize(event);
}
private onMessage(event: MessageEvent) {
const iframe = this.content.nativeElement as HTMLIFrameElement;
if (event.source != iframe.contentWindow) return;
const data = event.data as Package;
if (data.method == 'get') {
const pkg: Package = {method: "get", content: this.handleGet(data)};
iframe.contentWindow.postMessage(pkg, event.origin);
}
else if (data.method == 'set') {
this.handleSet(data);
}
else if (data.method == 'action') {
const pkg: Package = {method: "action", content: this.handleAction(data)};
if (data.action != 'closeSelf' && (data.action == 'closeWindow' && data.content.uuid == this.uuid))
iframe.contentWindow.postMessage(pkg, event.origin);
}
}
private handleGet(data: Package): any {
const element: HTMLElement = this.wrapper.nativeElement;
switch (data.variable) {
case "title":
return this.title;
case "maximized":
return this.maximized;
case "minimized":
return this.object.nativeElement.style.display == 'none';
case "draggable":
return this.draggable;
case "resizable":
return this.maximized;
case "position":
const x = element.offsetLeft;
const y = element.offsetTop;
return {x, y};
case "size":
const width = element.offsetWidth;
const height = element.offsetHeight;
return {width, height};
case "uuid":
return this.uuid;
}
}
private handleSet(data: Package) {
const element: HTMLElement = this.wrapper.nativeElement;
switch (data.variable) {
case "title":
this.title = data.content;
break;
case "maximized":
if (this.maximized != data.content)
this.toggleMaximized();
break;
case "minimized":
if ((this.object.nativeElement.style.display == 'none') != data.content)
this.toggleMinimized();
break;
case "draggable":
this.draggable = data.content;
break;
case "resizable":
this.resizable = data.content;
break;
case "position":
element.style.left = data.content.x + "px";
element.style.top = data.content.y + "px";
const x = data.content.x, y = data.content.y;
this.dispatchEvent({type: "move", data: {fromDrag: false, x, y}});
break;
case "size":
element.style.width = data.content.width + "px";
element.style.height = data.content.height + "px";
break;
}
}
private handleAction(data: Package): any {
switch (data.action) {
case "openWindow":
return DesktopComponent.instance.openProgram(data.content.identifier, data.content.args, data.content.asPopup);
case "closeWindow":
const window = DesktopComponent.instance.getWindow(data.content.uuid);
if (window == undefined) return false;
window.close();
return true;
case "messageWindow":
const target = DesktopComponent.instance.getWindow(data.content.uuid);
if (target == undefined) return false;
target.receiveMessageFromWindow(this, data.content.data);
return true;
case "closeSelf":
this.close();
return;
case "focus":
this.focus();
return;
case "notification":
DesktopComponent.instance.sendNotification(data.content);
return;
case "popup":
console.log("POPUP");
return undefined;
}
}
public dispatchEvent(event: WindowEvent) {
const iframe = this.content.nativeElement as HTMLIFrameElement;
const pkg: Package = {method: "event", event: event.type, content: event};
iframe.contentWindow.postMessage(pkg, new URL(iframe.src).origin);
}
}
class DragHandler {
@@ -125,16 +281,18 @@ class DragHandler {
public dragging: boolean;
private origTransitions: string;
public constructor(private object: HTMLElement, private wrapper: WindowWrapper) {
}
public constructor(private object: HTMLElement, private wrapper: WindowWrapper) {}
public windowDrag(event: MouseEvent): void {
if (!this.wrapper.draggable) return;
if (!this.dragging) return;
if (!this.wrapper.contentLoaded) return;
const x = event.clientX - this.offsetX;
const y = event.clientY - this.offsetY;
this.object.style.left = x + 'px';
this.object.style.top = y + 'px';
this.wrapper.dispatchEvent({type: "move", data: {fromDrag: true, x, y}});
}
public windowDragStart(event: MouseEvent): void {
@@ -168,8 +326,7 @@ class ResizeHandler {
public resizing: boolean = false;
private lastResizeManager: string;
public constructor(private object: HTMLElement, private wrapper: WindowWrapper) {
}
public constructor(private object: HTMLElement, private wrapper: WindowWrapper) {}
public windowResizeStart(event: MouseEvent): void {
if (this.wrapper.maximized) return;
@@ -191,6 +348,7 @@ class ResizeHandler {
}
public windowResize(event: MouseEvent) {
if (!this.wrapper.resizable) return;
if (!this.wrapper.focused) return;
if (this.wrapper.maximized) return;
@@ -245,6 +403,8 @@ class ResizeHandler {
if (newDimensions.y) this.object.style.top = newDimensions.y + 'px';
if (newDimensions.width) this.object.style.width = newDimensions.width + 'px';
if (newDimensions.height) this.object.style.height = newDimensions.height + 'px';
this.wrapper.dispatchEvent({type: "resize", data: newDimensions});
}
private isHoverBorder(event: MouseEvent): string {

View File

@@ -1,6 +1,7 @@
import {ChangeDetectorRef, Component, OnInit, ViewChild, ViewContainerRef} from '@angular/core';
import {TaskbarIcon} from "./taskbar-icon/taskbar-icon.component";
import {WindowWrapper} from "../../components/window-wrapper/window-wrapper.component";
import {Notification} from "webdesktop_windowapi/dist/helper/Notification";
export interface IconType {
uuid: number;
@@ -20,10 +21,10 @@ export interface ProgramArgs {
}
export const programs: {[programUUID: string]: ProgramArgs} = {
['defender']: {
identifier: 'defender',
name: 'Windows Defender',
handlerUrl: 'http://localhost:4200/',
['tester']: {
identifier: 'tester',
name: 'WindowAPI Tester',
handlerUrl: 'http://localhost:8080/',
}
}
@@ -56,18 +57,18 @@ export class DesktopComponent implements OnInit {
document.addEventListener('mousemove', this.mouseMove);
setTimeout(() => {
this.addTaskbarIcon(programs['defender']);
this.addTaskbarIcon(programs['tester']);
});
}
public openProgram(programUUID: string) {
public openProgram(programUUID: string, args?: string[], asPopup?: boolean): number {
const program = programs[programUUID];
const exists = this.getTaskbarIcon(programUUID) != undefined;
if (!exists)
this.addTaskbarIcon(program, true);
this.getTaskbarIcon(programUUID).icon.openProgram();
return this.getTaskbarIcon(programUUID).icon.openProgram(args, asPopup);
}
public addTaskbarIcon(program: ProgramArgs, removeOnClose: boolean = false, index?: number) {
@@ -132,6 +133,10 @@ export class DesktopComponent implements OnInit {
return uuid;
}
public sendNotification(notification: Notification) {
console.log(notification);
}
public mouseMove(event: MouseEvent) {
DesktopComponent.focusedWindow?.onMove(event);
}

View File

@@ -21,14 +21,15 @@ export class TaskbarIcon {
this.type = type;
}
public openProgram() {
public openProgram(args?: string[], asPopup: boolean = false): number {
const window = DesktopComponent.windowContainer.createComponent(WindowWrapper);
window.instance.program = this.type.program;
DesktopComponent.instance.cdr.detectChanges();
window.instance.initialize(this);
window.instance.initialize(this, args || [], asPopup);
this.windows.push(window.instance);
this.setIndicator('wide');
return window.instance.uuid;
}
public onTaskbarClick(event: MouseEvent) {