123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- // Copyright 2018 Google LLC
- //
- // 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
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "include/window_size/window_size_plugin.h"
- #include <flutter_linux/flutter_linux.h>
- #include <gtk/gtk.h>
- // See window_size_channel.dart for documentation.
- const char kChannelName[] = "flutter/windowsize";
- const char kBadArgumentsError[] = "Bad Arguments";
- const char kNoScreenError[] = "No Screen";
- const char kGetScreenListMethod[] = "getScreenList";
- const char kGetWindowInfoMethod[] = "getWindowInfo";
- const char kSetWindowFrameMethod[] = "setWindowFrame";
- const char kSetWindowMinimumSizeMethod[] = "setWindowMinimumSize";
- const char kSetWindowMaximumSizeMethod[] = "setWindowMaximumSize";
- const char kSetWindowTitleMethod[] = "setWindowTitle";
- const char ksetWindowVisibilityMethod[] = "setWindowVisibility";
- const char kGetWindowMinimumSizeMethod[] = "getWindowMinimumSize";
- const char kGetWindowMaximumSizeMethod[] = "getWindowMaximumSize";
- const char kFrameKey[] = "frame";
- const char kVisibleFrameKey[] = "visibleFrame";
- const char kScaleFactorKey[] = "scaleFactor";
- const char kScreenKey[] = "screen";
- struct _FlWindowSizePlugin {
- GObject parent_instance;
- FlPluginRegistrar* registrar;
- // Connection to Flutter engine.
- FlMethodChannel* channel;
- // Requested window geometry.
- GdkGeometry window_geometry;
- };
- G_DEFINE_TYPE(FlWindowSizePlugin, fl_window_size_plugin, g_object_get_type())
- // Gets the window being controlled.
- GtkWindow* get_window(FlWindowSizePlugin* self) {
- FlView* view = fl_plugin_registrar_get_view(self->registrar);
- if (view == nullptr) return nullptr;
- return GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)));
- }
- // Gets the display connection.
- GdkDisplay* get_display(FlWindowSizePlugin* self) {
- FlView* view = fl_plugin_registrar_get_view(self->registrar);
- if (view == nullptr) return nullptr;
- return gtk_widget_get_display(GTK_WIDGET(view));
- }
- // Converts frame dimensions into the Flutter representation.
- FlValue* make_frame_value(gint x, gint y, gint width, gint height) {
- g_autoptr(FlValue) value = fl_value_new_list();
- fl_value_append_take(value, fl_value_new_float(x));
- fl_value_append_take(value, fl_value_new_float(y));
- fl_value_append_take(value, fl_value_new_float(width));
- fl_value_append_take(value, fl_value_new_float(height));
- return fl_value_ref(value);
- }
- // Converts monitor information into the Flutter representation.
- FlValue* make_monitor_value(GdkMonitor* monitor) {
- g_autoptr(FlValue) value = fl_value_new_map();
- GdkRectangle frame;
- gdk_monitor_get_geometry(monitor, &frame);
- fl_value_set_string_take(
- value, kFrameKey,
- make_frame_value(frame.x, frame.y, frame.width, frame.height));
- gdk_monitor_get_workarea(monitor, &frame);
- fl_value_set_string_take(
- value, kVisibleFrameKey,
- make_frame_value(frame.x, frame.y, frame.width, frame.height));
- gint scale_factor = gdk_monitor_get_scale_factor(monitor);
- fl_value_set_string_take(value, kScaleFactorKey,
- fl_value_new_float(scale_factor));
- return fl_value_ref(value);
- }
- // Gets the list of current screens.
- static FlMethodResponse* get_screen_list(FlWindowSizePlugin* self) {
- g_autoptr(FlValue) screens = fl_value_new_list();
- GdkDisplay* display = get_display(self);
- if (display == nullptr) {
- return FL_METHOD_RESPONSE(
- fl_method_error_response_new(kNoScreenError, nullptr, nullptr));
- }
- gint n_monitors = gdk_display_get_n_monitors(display);
- for (gint i = 0; i < n_monitors; i++) {
- GdkMonitor* monitor = gdk_display_get_monitor(display, i);
- fl_value_append_take(screens, make_monitor_value(monitor));
- }
- return FL_METHOD_RESPONSE(fl_method_success_response_new(screens));
- }
- // Gets information about the Flutter window.
- static FlMethodResponse* get_window_info(FlWindowSizePlugin* self) {
- GtkWindow* window = get_window(self);
- if (window == nullptr) {
- return FL_METHOD_RESPONSE(
- fl_method_error_response_new(kNoScreenError, nullptr, nullptr));
- }
- g_autoptr(FlValue) window_info = fl_value_new_map();
- gint x, y, width, height;
- gtk_window_get_position(window, &x, &y);
- gtk_window_get_size(window, &width, &height);
- fl_value_set_string_take(window_info, kFrameKey,
- make_frame_value(x, y, width, height));
- // Get the monitor this window is inside, or the primary monitor if doesn't
- // appear to be in any.
- GdkDisplay* display = get_display(self);
- GdkMonitor* monitor_with_window = gdk_display_get_primary_monitor(display);
- int n_monitors = gdk_display_get_n_monitors(display);
- for (int i = 0; i < n_monitors; i++) {
- GdkMonitor* monitor = gdk_display_get_monitor(display, i);
- GdkRectangle frame;
- gdk_monitor_get_geometry(monitor, &frame);
- if ((x >= frame.x && x <= frame.x + frame.width) &&
- (y >= frame.y && y <= frame.y + frame.width)) {
- monitor_with_window = monitor;
- break;
- }
- }
- fl_value_set_string_take(window_info, kScreenKey,
- make_monitor_value(monitor_with_window));
- gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(window));
- fl_value_set_string_take(window_info, kScaleFactorKey,
- fl_value_new_float(scale_factor));
- return FL_METHOD_RESPONSE(fl_method_success_response_new(window_info));
- }
- // Sets the window position and dimensions.
- static FlMethodResponse* set_window_frame(FlWindowSizePlugin* self,
- FlValue* args) {
- if (fl_value_get_type(args) != FL_VALUE_TYPE_LIST ||
- fl_value_get_length(args) != 4) {
- return FL_METHOD_RESPONSE(fl_method_error_response_new(
- kBadArgumentsError, "Expected 4-element list", nullptr));
- }
- double x = fl_value_get_float(fl_value_get_list_value(args, 0));
- double y = fl_value_get_float(fl_value_get_list_value(args, 1));
- double width = fl_value_get_float(fl_value_get_list_value(args, 2));
- double height = fl_value_get_float(fl_value_get_list_value(args, 3));
- GtkWindow* window = get_window(self);
- if (window == nullptr) {
- return FL_METHOD_RESPONSE(
- fl_method_error_response_new(kNoScreenError, nullptr, nullptr));
- }
- gtk_window_move(window, static_cast<gint>(x), static_cast<gint>(y));
- gtk_window_resize(window, static_cast<gint>(width),
- static_cast<gint>(height));
- return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
- }
- // Send updated window geometry to GTK.
- static void update_window_geometry(FlWindowSizePlugin* self) {
- gtk_window_set_geometry_hints(
- get_window(self), nullptr, &self->window_geometry,
- static_cast<GdkWindowHints>(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
- }
- // Sets the window minimum size.
- static FlMethodResponse* set_window_minimum_size(FlWindowSizePlugin* self,
- FlValue* args) {
- if (fl_value_get_type(args) != FL_VALUE_TYPE_LIST ||
- fl_value_get_length(args) != 2) {
- return FL_METHOD_RESPONSE(fl_method_error_response_new(
- kBadArgumentsError, "Expected 2-element list", nullptr));
- }
- double width = fl_value_get_float(fl_value_get_list_value(args, 0));
- double height = fl_value_get_float(fl_value_get_list_value(args, 1));
- if (get_window(self) == nullptr) {
- return FL_METHOD_RESPONSE(
- fl_method_error_response_new(kNoScreenError, nullptr, nullptr));
- }
- if (width >= 0 && height >= 0) {
- self->window_geometry.min_width = static_cast<gint>(width);
- self->window_geometry.min_height = static_cast<gint>(height);
- }
- update_window_geometry(self);
- return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
- }
- // Sets the window maximum size.
- static FlMethodResponse* set_window_maximum_size(FlWindowSizePlugin* self,
- FlValue* args) {
- if (fl_value_get_type(args) != FL_VALUE_TYPE_LIST ||
- fl_value_get_length(args) != 2) {
- return FL_METHOD_RESPONSE(fl_method_error_response_new(
- kBadArgumentsError, "Expected 2-element list", nullptr));
- }
- double width = fl_value_get_float(fl_value_get_list_value(args, 0));
- double height = fl_value_get_float(fl_value_get_list_value(args, 1));
- if (get_window(self) == nullptr) {
- return FL_METHOD_RESPONSE(
- fl_method_error_response_new(kNoScreenError, nullptr, nullptr));
- }
- self->window_geometry.max_width = static_cast<gint>(width);
- self->window_geometry.max_height = static_cast<gint>(height);
- // Flutter uses -1 as unconstrained, GTK doesn't have an unconstrained value.
- if (self->window_geometry.max_width < 0) {
- self->window_geometry.max_width = G_MAXINT;
- }
- if (self->window_geometry.max_height < 0) {
- self->window_geometry.max_height = G_MAXINT;
- }
- update_window_geometry(self);
- return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
- }
- // Sets the window title.
- static FlMethodResponse* set_window_title(FlWindowSizePlugin* self,
- FlValue* args) {
- if (fl_value_get_type(args) != FL_VALUE_TYPE_STRING) {
- return FL_METHOD_RESPONSE(fl_method_error_response_new(
- kBadArgumentsError, "Expected string", nullptr));
- }
- GtkWindow* window = get_window(self);
- if (window == nullptr) {
- return FL_METHOD_RESPONSE(
- fl_method_error_response_new(kNoScreenError, nullptr, nullptr));
- }
- gtk_window_set_title(window, fl_value_get_string(args));
- return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
- }
- // Sets the window visibility.
- static FlMethodResponse* set_window_visible(FlWindowSizePlugin* self,
- FlValue* args) {
- if (fl_value_get_type(args) != FL_VALUE_TYPE_BOOL) {
- return FL_METHOD_RESPONSE(fl_method_error_response_new(
- kBadArgumentsError, "Expected bool", nullptr));
- }
- GtkWindow* window = get_window(self);
- if (window == nullptr) {
- return FL_METHOD_RESPONSE(
- fl_method_error_response_new(kNoScreenError, nullptr, nullptr));
- }
- if (fl_value_get_bool(args)) {
- gtk_widget_show(GTK_WIDGET(window));
- } else {
- gtk_widget_hide(GTK_WIDGET(window));
- }
- return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
- }
- // Gets the window minimum size.
- static FlMethodResponse* get_window_minimum_size(FlWindowSizePlugin* self) {
- g_autoptr(FlValue) size = fl_value_new_list();
- gint min_width = self->window_geometry.min_width;
- gint min_height = self->window_geometry.min_height;
- // GTK uses -1 for the requisition size (the size GTK has calculated).
- // Report this as zero (smallest possible) so this doesn't look like Size(-1, -1).
- if (min_width < 0) {
- min_width = 0;
- }
- if (min_height < 0) {
- min_height = 0;
- }
- fl_value_append_take(size, fl_value_new_float(min_width));
- fl_value_append_take(size, fl_value_new_float(min_height));
- return FL_METHOD_RESPONSE(fl_method_success_response_new(size));
- }
- // Gets the window maximum size.
- static FlMethodResponse* get_window_maximum_size(FlWindowSizePlugin* self) {
- g_autoptr(FlValue) size = fl_value_new_list();
- gint max_width = self->window_geometry.max_width;
- gint max_height = self->window_geometry.max_height;
- // Flutter uses -1 as unconstrained, GTK doesn't have an unconstrained value.
- if (max_width == G_MAXINT) {
- max_width = -1;
- }
- if (max_height == G_MAXINT) {
- max_height = -1;
- }
- fl_value_append_take(size, fl_value_new_float(max_width));
- fl_value_append_take(size, fl_value_new_float(max_height));
- return FL_METHOD_RESPONSE(fl_method_success_response_new(size));
- }
- // Called when a method call is received from Flutter.
- static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call,
- gpointer user_data) {
- FlWindowSizePlugin* self = FL_WINDOW_SIZE_PLUGIN(user_data);
- const gchar* method = fl_method_call_get_name(method_call);
- FlValue* args = fl_method_call_get_args(method_call);
- g_autoptr(FlMethodResponse) response = nullptr;
- if (strcmp(method, kGetScreenListMethod) == 0) {
- response = get_screen_list(self);
- } else if (strcmp(method, kGetWindowInfoMethod) == 0) {
- response = get_window_info(self);
- } else if (strcmp(method, kSetWindowFrameMethod) == 0) {
- response = set_window_frame(self, args);
- } else if (strcmp(method, kSetWindowMinimumSizeMethod) == 0) {
- response = set_window_minimum_size(self, args);
- } else if (strcmp(method, kSetWindowMaximumSizeMethod) == 0) {
- response = set_window_maximum_size(self, args);
- } else if (strcmp(method, kSetWindowTitleMethod) == 0) {
- response = set_window_title(self, args);
- } else if (strcmp(method, ksetWindowVisibilityMethod) == 0) {
- response = set_window_visible(self, args);
- } else if (strcmp(method, kGetWindowMinimumSizeMethod) == 0) {
- response = get_window_minimum_size(self);
- } else if (strcmp(method, kGetWindowMaximumSizeMethod) == 0) {
- response = get_window_maximum_size(self);
- } else {
- response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
- }
- g_autoptr(GError) error = nullptr;
- if (!fl_method_call_respond(method_call, response, &error))
- g_warning("Failed to send method call response: %s", error->message);
- }
- static void fl_window_size_plugin_dispose(GObject* object) {
- FlWindowSizePlugin* self = FL_WINDOW_SIZE_PLUGIN(object);
- g_clear_object(&self->registrar);
- g_clear_object(&self->channel);
- G_OBJECT_CLASS(fl_window_size_plugin_parent_class)->dispose(object);
- }
- static void fl_window_size_plugin_class_init(FlWindowSizePluginClass* klass) {
- G_OBJECT_CLASS(klass)->dispose = fl_window_size_plugin_dispose;
- }
- static void fl_window_size_plugin_init(FlWindowSizePlugin* self) {
- self->window_geometry.min_width = -1;
- self->window_geometry.min_height = -1;
- self->window_geometry.max_width = G_MAXINT;
- self->window_geometry.max_height = G_MAXINT;
- }
- FlWindowSizePlugin* fl_window_size_plugin_new(FlPluginRegistrar* registrar) {
- FlWindowSizePlugin* self = FL_WINDOW_SIZE_PLUGIN(
- g_object_new(fl_window_size_plugin_get_type(), nullptr));
- self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar));
- g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
- self->channel =
- fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
- kChannelName, FL_METHOD_CODEC(codec));
- fl_method_channel_set_method_call_handler(self->channel, method_call_cb,
- g_object_ref(self), g_object_unref);
- return self;
- }
- void window_size_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
- FlWindowSizePlugin* plugin = fl_window_size_plugin_new(registrar);
- g_object_unref(plugin);
- }
|