Skip to content

Commit 82a3869

Browse files
jpnurmislightfoot
authored andcommitted
WIP: battery_plus_linux in C++
NOTE! This depends on: - flutter/engine#21316 - flutter/engine#21405 Ref: #4 Ref: #5
1 parent ed2b99f commit 82a3869

File tree

17 files changed

+5134
-0
lines changed

17 files changed

+5134
-0
lines changed

packages/battery_plus/example/linux/flutter/generated_plugin_registrant.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
#include "generated_plugin_registrant.h"
66

7+
#include <battery_plus_linux/battery_plus_linux_plugin.h>
78

89
void fl_register_plugins(FlPluginRegistry* registry) {
10+
g_autoptr(FlPluginRegistrar) battery_plus_linux_registrar =
11+
fl_plugin_registry_get_registrar_for_plugin(registry, "BatteryPlusLinuxPlugin");
12+
battery_plus_linux_plugin_register_with_registrar(battery_plus_linux_registrar);
913
}

packages/battery_plus/example/linux/flutter/generated_plugins.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44

55
list(APPEND FLUTTER_PLUGIN_LIST
6+
battery_plus_linux
67
)
78

89
set(PLUGIN_BUNDLED_LIBRARIES)

packages/battery_plus/pubspec.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ flutter:
1111
pluginClass: BatteryPlugin
1212
ios:
1313
pluginClass: FLTBatteryPlugin
14+
linux:
15+
default_package: battery_plus_linux
1416
web:
1517
default_package: battery_plus_web
1618

1719
dependencies:
1820
flutter:
1921
sdk: flutter
2022
meta: ^1.0.5
23+
battery_plus_linux:
24+
path: ../battery_plus_linux
2125
battery_plus_platform_interface:
2226
path: ../battery_plus_platform_interface
2327
battery_plus_web:
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
12+
# IntelliJ related
13+
*.iml
14+
*.ipr
15+
*.iws
16+
.idea/
17+
18+
# The .vscode folder contains launch configuration and tasks you configure in
19+
# VS Code which you may wish to be included in version control, so this line
20+
# is commented out by default.
21+
#.vscode/
22+
23+
# Flutter/Dart/Pub related
24+
**/doc/api/
25+
.dart_tool/
26+
.flutter-plugins
27+
.flutter-plugins-dependencies
28+
.packages
29+
.pub-cache/
30+
.pub/
31+
build/
32+
33+
# Android related
34+
**/android/**/gradle-wrapper.jar
35+
**/android/.gradle
36+
**/android/captures/
37+
**/android/gradlew
38+
**/android/gradlew.bat
39+
**/android/local.properties
40+
**/android/**/GeneratedPluginRegistrant.java
41+
42+
# iOS/XCode related
43+
**/ios/**/*.mode1v3
44+
**/ios/**/*.mode2v3
45+
**/ios/**/*.moved-aside
46+
**/ios/**/*.pbxuser
47+
**/ios/**/*.perspectivev3
48+
**/ios/**/*sync/
49+
**/ios/**/.sconsign.dblite
50+
**/ios/**/.tags*
51+
**/ios/**/.vagrant/
52+
**/ios/**/DerivedData/
53+
**/ios/**/Icon?
54+
**/ios/**/Pods/
55+
**/ios/**/.symlinks/
56+
**/ios/**/profile
57+
**/ios/**/xcuserdata
58+
**/ios/.generated/
59+
**/ios/Flutter/App.framework
60+
**/ios/Flutter/Flutter.framework
61+
**/ios/Flutter/Flutter.podspec
62+
**/ios/Flutter/Generated.xcconfig
63+
**/ios/Flutter/app.flx
64+
**/ios/Flutter/app.zip
65+
**/ios/Flutter/flutter_assets/
66+
**/ios/Flutter/flutter_export_environment.sh
67+
**/ios/ServiceDefinitions.json
68+
**/ios/Runner/GeneratedPluginRegistrant.*
69+
70+
# Exceptions to above rules.
71+
!**/ios/**/default.mode1v3
72+
!**/ios/**/default.mode2v3
73+
!**/ios/**/default.pbxuser
74+
!**/ios/**/default.perspectivev3
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: 34541c30735bc1086335e13d69a7e0acdc0538c5
8+
channel: master
9+
10+
project_type: package
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 The Flutter Community Plus Plugin Authors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Battery Plus Linux
2+
3+
[![Flutter Community: battery_plus_linux](https://fluttercommunity.dev/_github/header/battery_plus_linux)](https://github.com/fluttercommunity/community)
4+
5+
[![pub package](https://img.shields.io/pub/v/battery_plus_linux.svg)](https://pub.dev/packages/battery_plus_linux)
6+
7+
The Linux implementation of [`battery_plus`](https://pub.dev/packages/battery_plus).
8+
9+
## Usage
10+
11+
This package is already included as part of the `battery_plus` package dependency, and will
12+
be included when using `battery_plus` as normal.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// The battery_plus_platform_interface defaults to MethodChannelBattery
2+
// as its instance, which is all the Linux implementation needs. This file
3+
// is here to silence warnings when publishing to pub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
set(PROJECT_NAME "battery_plus_linux")
3+
project(${PROJECT_NAME} LANGUAGES CXX C)
4+
5+
set(PLUGIN_NAME "${PROJECT_NAME}_plugin")
6+
7+
add_library(${PLUGIN_NAME} SHARED
8+
"${PLUGIN_NAME}.cc"
9+
upower_device.c
10+
)
11+
apply_standard_settings(${PLUGIN_NAME})
12+
set_target_properties(${PLUGIN_NAME} PROPERTIES
13+
CXX_VISIBILITY_PRESET hidden)
14+
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
15+
target_include_directories(${PLUGIN_NAME} INTERFACE
16+
"${CMAKE_CURRENT_SOURCE_DIR}/include")
17+
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
18+
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK)
19+
20+
# List of absolute paths to libraries that should be bundled with the plugin
21+
set(battery_plus_linux_bundled_libraries
22+
""
23+
PARENT_SCOPE
24+
)
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#include "include/battery_plus_linux/battery_plus_linux_plugin.h"
2+
#include "upower_device.h"
3+
4+
#include <flutter_linux/flutter_linux.h>
5+
#include <gtk/gtk.h>
6+
#include <cmath>
7+
8+
#define BATTERY_PLUS_LINUX_PLUGIN(obj) \
9+
(G_TYPE_CHECK_INSTANCE_CAST((obj), battery_plus_linux_plugin_get_type(), \
10+
BatteryPlusLinuxPlugin))
11+
12+
static const char* kMethodChannel = "plugins.flutter.io/battery";
13+
static const char* kEventChannel = "plugins.flutter.io/charging";
14+
static const char* kBatteryLevelMethod = "getBatteryLevel";
15+
static const char* kDbusError = "D-BUS Error";
16+
static const char* kDbusInterface = "org.freedesktop.UPower";
17+
static const char* kDbusObject = "/org/freedesktop/UPower/devices/DisplayDevice";
18+
19+
struct _BatteryPlusLinuxPlugin {
20+
GObject parent_instance;
21+
UPowerDevice* state_device = nullptr;
22+
};
23+
24+
G_DEFINE_TYPE(BatteryPlusLinuxPlugin, battery_plus_linux_plugin, g_object_get_type())
25+
26+
enum UPowerState {
27+
Unknown = 0,
28+
Charging = 1,
29+
Discharging = 2,
30+
Empty = 3,
31+
FullyCharged = 4,
32+
PendingCharge = 5,
33+
PendingDischarge = 6
34+
};
35+
36+
// ### TODO: introduce a new 'unknown' battery state for workstations?
37+
static const gchar *upower_state_str(guint state) {
38+
switch (state) {
39+
case Charging:
40+
return "charging";
41+
case Discharging:
42+
return "discharging";
43+
default:
44+
return "full";
45+
}
46+
}
47+
48+
static UPowerDevice* upower_device_new(FlMethodResponse **response) {
49+
g_autoptr(GError) error = nullptr;
50+
UPowerDevice* device = upower_device_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
51+
G_DBUS_PROXY_FLAGS_NONE,
52+
kDbusInterface,
53+
kDbusObject,
54+
nullptr,
55+
&error);
56+
if (error) {
57+
*response = FL_METHOD_RESPONSE(fl_method_error_response_new(kDbusError,
58+
error->message,
59+
nullptr));
60+
}
61+
return device;
62+
}
63+
64+
static void battery_plus_linux_plugin_handle_method_call(BatteryPlusLinuxPlugin* self,
65+
FlMethodCall* method_call) {
66+
g_autoptr(FlMethodResponse) response = nullptr;
67+
const gchar* method_name = fl_method_call_get_name(method_call);
68+
if (strcmp(method_name, kBatteryLevelMethod) == 0) {
69+
UPowerDevice* device = upower_device_new(&response);
70+
if (!response) {
71+
gdouble level = upower_device_get_percentage(device);
72+
g_autoptr(FlValue) result = fl_value_new_int(std::round(level));
73+
g_object_unref(device);
74+
response = FL_METHOD_RESPONSE(fl_method_success_response_new(result));
75+
}
76+
} else {
77+
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
78+
}
79+
fl_method_call_respond(method_call, response, nullptr);
80+
}
81+
82+
static void send_battery_state_event(FlEventChannel *event_channel, guint state) {
83+
g_autoptr(FlValue) message = fl_value_new_string(upower_state_str(state));
84+
g_autoptr(GError) error = nullptr;
85+
if (!fl_event_channel_send(event_channel, message, NULL, &error)) {
86+
g_warning("Failed to send event: %s", error->message);
87+
}
88+
}
89+
90+
static void properties_changed_cb(GDBusProxy* proxy,
91+
GVariant* changed_properties,
92+
const gchar* invalidated_properties,
93+
gpointer user_data)
94+
{
95+
GVariant* value = g_variant_lookup_value(changed_properties,
96+
"State",
97+
G_VARIANT_TYPE_UINT32);
98+
if (value) {
99+
guint32 state = g_variant_get_uint32(value);
100+
send_battery_state_event(FL_EVENT_CHANNEL(user_data), state);
101+
}
102+
}
103+
104+
static FlMethodErrorResponse* battery_plus_linux_plugin_listen_events(BatteryPlusLinuxPlugin* self,
105+
FlEventChannel* event_channel,
106+
FlValue* args) {
107+
FlMethodResponse *response = nullptr;
108+
self->state_device = upower_device_new(&response);
109+
if (self->state_device) {
110+
g_signal_connect(self->state_device,
111+
"g-properties-changed",
112+
G_CALLBACK(properties_changed_cb),
113+
event_channel);
114+
}
115+
send_battery_state_event(event_channel, upower_device_get_state(self->state_device));
116+
return FL_METHOD_ERROR_RESPONSE(response);
117+
}
118+
119+
static FlMethodErrorResponse* battery_plus_linux_plugin_cancel_events(BatteryPlusLinuxPlugin* self,
120+
FlEventChannel* event_channel,
121+
FlValue* args) {
122+
g_clear_object(&self->state_device);
123+
return nullptr;
124+
}
125+
126+
static void battery_plus_linux_plugin_dispose(GObject* object) {
127+
G_OBJECT_CLASS(battery_plus_linux_plugin_parent_class)->dispose(object);
128+
}
129+
130+
static void battery_plus_linux_plugin_class_init(BatteryPlusLinuxPluginClass* klass) {
131+
G_OBJECT_CLASS(klass)->dispose = battery_plus_linux_plugin_dispose;
132+
}
133+
134+
static void battery_plus_linux_plugin_init(BatteryPlusLinuxPlugin* self) { }
135+
136+
static void method_call_cb(FlMethodChannel* method_channel,
137+
FlMethodCall* method_call,
138+
gpointer user_data) {
139+
BatteryPlusLinuxPlugin* plugin = BATTERY_PLUS_LINUX_PLUGIN(user_data);
140+
battery_plus_linux_plugin_handle_method_call(plugin, method_call);
141+
}
142+
143+
static FlMethodErrorResponse* listen_cb(FlEventChannel* event_channel,
144+
FlValue* args,
145+
gpointer user_data) {
146+
BatteryPlusLinuxPlugin* plugin = BATTERY_PLUS_LINUX_PLUGIN(user_data);
147+
return battery_plus_linux_plugin_listen_events(plugin, event_channel, args);
148+
}
149+
150+
static FlMethodErrorResponse* cancel_cb(FlEventChannel* event_channel,
151+
FlValue* args,
152+
gpointer user_data) {
153+
BatteryPlusLinuxPlugin* plugin = BATTERY_PLUS_LINUX_PLUGIN(user_data);
154+
return battery_plus_linux_plugin_cancel_events(plugin, event_channel, args);
155+
}
156+
157+
void battery_plus_linux_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
158+
BatteryPlusLinuxPlugin* plugin =
159+
BATTERY_PLUS_LINUX_PLUGIN(g_object_new(battery_plus_linux_plugin_get_type(), nullptr));
160+
161+
FlBinaryMessenger* messenger = fl_plugin_registrar_get_messenger(registrar);
162+
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
163+
164+
g_autoptr(FlMethodChannel) method_channel = fl_method_channel_new(messenger,
165+
kMethodChannel,
166+
FL_METHOD_CODEC(codec));
167+
fl_method_channel_set_method_call_handler(method_channel,
168+
method_call_cb,
169+
g_object_ref(plugin),
170+
g_object_unref);
171+
172+
g_autoptr(FlEventChannel) event_channel = fl_event_channel_new(messenger,
173+
kEventChannel,
174+
FL_METHOD_CODEC(codec));
175+
fl_event_channel_set_stream_handlers(event_channel,
176+
listen_cb,
177+
cancel_cb,
178+
g_object_ref(plugin),
179+
g_object_unref);
180+
181+
g_object_unref(plugin);
182+
}

0 commit comments

Comments
 (0)