-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: providing a minimal launcher written in flutter for ubuntu f…
…rame (#191) ## What's new? - Frame can now optionally support the `launcher`, which is a minimal dock allowing the user to switch between fullscreen application ## Documentation Ubuntu Frame's `launcher` daemon provides users with a way to navigate between multiple applications running on a single frame instance. ### Enablement To enable the launcher, run: ```sh snap set ubuntu-frame launcher=true ``` ### Behavior The following specifies the behavior that you can of the launcher daemon: - When frame starts, the launcher will appear in the left-hand side of the screen with a black background - As window are opened, the launcher will display an icon that corresponds with the application for that window - Icons will ONLY be displayed for applications that are packaged as snaps. The desktop files for these applications are found in the `/var/lib/snapd/desktop` directory. - When an icon is clicked, the corresponding window will be brought into focus - If a window is closed, then the icon will be removed from the launcher - If we cannot resolve an icon for a window, then the launcher will attempt to use the `application-x-executable` icon. If that fails, then the icon will be missing entirely.
- Loading branch information
Showing
39 changed files
with
2,740 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# See https://www.dartlang.org/guides/libraries/private-files | ||
|
||
# Files and directories created by pub | ||
.dart_tool/ | ||
.packages | ||
build/ | ||
# If you're building an application, you may want to check-in your pubspec.lock | ||
pubspec.lock | ||
|
||
# Directory created by dartdoc | ||
# If you don't generate documentation locally you can remove this line. | ||
doc/api/ | ||
|
||
# dotenv environment variables file | ||
.env* | ||
|
||
# Avoid committing generated Javascript files: | ||
*.dart.js | ||
*.info.json # Produced by the --dump-info flag. | ||
*.js # When generated by dart2js. Don't specify *.js if your | ||
# project includes source files written in JavaScript. | ||
*.js_ | ||
*.js.deps | ||
*.js.map | ||
|
||
.flutter-plugins | ||
.flutter-plugins-dependencies | ||
|
||
linux/flutter/ephemeral |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# ubuntu-frame-launcher | ||
A flutter-based launcher for Ubuntu Frame. | ||
|
||
## Install | ||
```sh | ||
flutter pub get | ||
``` | ||
|
||
## Development | ||
1 . Run `ubuntu-frame`: | ||
|
||
```sh | ||
WAYLAND_DISPLAY=wayland-98 ubuntu-frame --add-wayland-extensions zwlr_layer_shell_v1:zwlr_foreign_toplevel_manager_v1 | ||
``` | ||
|
||
2. Run `launcher`: | ||
|
||
```sh | ||
cd launcher | ||
WAYLAND_DISPLAY=wayland-98 flutter run | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# This file configures the analyzer, which statically analyzes Dart code to | ||
# check for errors, warnings, and lints. | ||
# | ||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled | ||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be | ||
# invoked from the command line by running `flutter analyze`. | ||
|
||
# The following line activates a set of recommended lints for Flutter apps, | ||
# packages, and plugins designed to encourage good coding practices. | ||
include: package:flutter_lints/flutter.yaml | ||
|
||
linter: | ||
# The lint rules applied to this project can be customized in the | ||
# section below to disable rules from the `package:flutter_lints/flutter.yaml` | ||
# included above or to enable additional rules. A list of all available lints | ||
# and their documentation is published at | ||
# https://dart-lang.github.io/linter/lints/index.html. | ||
# | ||
# Instead of disabling a lint rule for the entire project in the | ||
# section below, it can also be suppressed for a single line of code | ||
# or a specific dart file by using the `// ignore: name_of_lint` and | ||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file | ||
# producing the lint. | ||
rules: | ||
# avoid_print: false # Uncomment to disable the `avoid_print` rule | ||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule | ||
|
||
# Additional information about this file can be found at | ||
# https://dart.dev/guides/language/analysis-options |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* | ||
* Copyright © Canonical Ltd. | ||
* | ||
* This program is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 or 3, | ||
* as published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
import 'dart:async'; | ||
|
||
import 'package:logging/logging.dart'; | ||
import 'package:ubuntu_frame_launcher/models/desktop_file.dart'; | ||
import 'package:ubuntu_frame_launcher/models/window_event.dart'; | ||
import 'package:ubuntu_frame_launcher/services/window_service.dart'; | ||
|
||
import '../services/desktop_file_manager.dart'; | ||
|
||
class ApplicationController { | ||
final WindowService windowService; | ||
final DesktopFileManager desktopFileManager; | ||
|
||
final _controller = StreamController<List<DesktopFile>>.broadcast(); | ||
late Future<List<DesktopFile>> _installedAppFuture; | ||
final _logger = Logger("ApplicationController"); | ||
|
||
ApplicationController(this.windowService, this.desktopFileManager) { | ||
_installedAppFuture = _loadInstalledApplications(); | ||
|
||
windowService.watcher.listen((event) async { | ||
if (event.eventType == WindowEventType.created || | ||
event.eventType == WindowEventType.removed) { | ||
_controller.add(await getOpenApplications()); | ||
} | ||
}); | ||
} | ||
|
||
Future<List<DesktopFile>> _loadInstalledApplications() async { | ||
final applications = await desktopFileManager.getAllDesktopFiles(); | ||
applications.sort((a, b) { | ||
final aName = a.name?.toLowerCase() ?? ''; | ||
final bName = b.name?.toLowerCase() ?? ''; | ||
return aName.compareTo(bName); | ||
}); | ||
return applications; | ||
} | ||
|
||
/// Returns a list of applications installed on the system. This list | ||
/// is guaranteed to be sorted alphabetically by name. | ||
Future<List<DesktopFile>> getInstalledApplications() async { | ||
// TODO: Watch directories and dynamically reload if they change | ||
return await _installedAppFuture; | ||
} | ||
|
||
void focus(DesktopFile file) { | ||
final handle = windowService.getWindowById(file.id); | ||
if (handle != null) { | ||
handle.activate(); | ||
return; | ||
} | ||
|
||
_logger.shout("Unable to focus desktop file with id = ${file.id}}"); | ||
} | ||
|
||
Stream<List<DesktopFile>> getOpenedAppsStream() { | ||
return _controller.stream; | ||
} | ||
|
||
Future<List<DesktopFile>> getOpenApplications() async { | ||
final List<DesktopFile> result = []; | ||
for (final handle in windowService.getWindowList()) { | ||
result.add(await desktopFileManager.resolveId(handle.getAppId())); | ||
} | ||
|
||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright © Canonical Ltd. | ||
* | ||
* This program is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 or 3, | ||
* as published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
import 'package:ubuntu_frame_launcher/models/desktop_file.dart'; | ||
import 'package:ubuntu_frame_launcher/services/window_handle.dart'; | ||
|
||
import '../services/window_service.dart'; | ||
|
||
class WindowController { | ||
WindowService service; | ||
|
||
WindowController(this.service); | ||
|
||
WindowHandle? getWindowById(String appId) { | ||
return service.getWindowById(appId); | ||
} | ||
|
||
List<WindowHandle> getWindowList() { | ||
return service.getWindowList(); | ||
} | ||
|
||
bool isOpen(DesktopFile file) { | ||
return service.getWindowById(file.id) != null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright © Canonical Ltd. | ||
* | ||
* This program is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 or 3, | ||
* as published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:ubuntu_frame_launcher/services/wayland_window_watcher.dart'; | ||
import 'package:ubuntu_frame_launcher/controllers/window_controller.dart'; | ||
import 'package:ubuntu_frame_launcher/services/window_service.dart'; | ||
import 'services/desktop_file_manager.dart'; | ||
import 'package:get_it/get_it.dart'; | ||
import 'views/dock.dart'; | ||
import 'controllers/application_controller.dart'; | ||
import 'package:logging/logging.dart'; | ||
|
||
void main() async { | ||
Logger.root.level = Level.ALL; // defaults to Level.INFO | ||
Logger.root.onRecord.listen((record) { | ||
print('${record.level.name}: ${record.time}: ${record.message}'); | ||
}); | ||
|
||
final logger = Logger("main"); | ||
logger.info("Ubuntu Frame launcher is starting"); | ||
|
||
final getIt = GetIt.instance; | ||
|
||
// Services | ||
getIt.registerLazySingleton<WindowService>( | ||
() => WindowService(WaylandWindowWatcherService())); | ||
getIt.registerLazySingleton<DesktopFileManager>(() => DesktopFileManager()); | ||
|
||
// Controllers | ||
getIt.registerLazySingleton<ApplicationController>(() => | ||
ApplicationController( | ||
getIt.get<WindowService>(), getIt.get<DesktopFileManager>())); | ||
getIt.registerLazySingleton<WindowController>( | ||
() => WindowController(getIt.get<WindowService>())); | ||
|
||
runApp(const LauncherApp()); | ||
} | ||
|
||
class LauncherApp extends StatelessWidget { | ||
const LauncherApp({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return MaterialApp( | ||
theme: ThemeData( | ||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.black), | ||
primaryColor: Colors.black, | ||
useMaterial3: true, | ||
fontFamily: 'Ubuntu', | ||
iconTheme: const IconThemeData(color: Colors.white, size: 20), | ||
textTheme: const TextTheme( | ||
bodyMedium: TextStyle( | ||
color: Colors.white, | ||
), | ||
)), | ||
home: const Launcher(), | ||
); | ||
} | ||
} | ||
|
||
class Launcher extends StatelessWidget { | ||
const Launcher({super.key}); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Scaffold( | ||
body: Column( | ||
mainAxisSize: MainAxisSize.min, | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: <Widget>[Dock()], | ||
)); | ||
} | ||
} |
Oops, something went wrong.