Skip to content

Commit b00a158

Browse files
authored
Introduce grabKeyboard() and ungrabKeyboard() (#229)
Implemented for Linux, so far.
1 parent d8f6ccd commit b00a158

File tree

3 files changed

+113
-3
lines changed

3 files changed

+113
-3
lines changed

example/lib/pages/home.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,18 @@ class _HomePageState extends State<HomePage> with TrayListener, WindowListener {
830830
);
831831
},
832832
),
833+
PreferenceListItem(
834+
title: Text('grabKeyboard'),
835+
onTap: () async {
836+
await windowManager.grabKeyboard();
837+
},
838+
),
839+
PreferenceListItem(
840+
title: Text('ungrabKeyboard'),
841+
onTap: () async {
842+
await windowManager.ungrabKeyboard();
843+
},
844+
),
833845
],
834846
),
835847
],

lib/src/window_manager.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,16 @@ class WindowManager {
649649
}..removeWhere((key, value) => value == null);
650650
await _channel.invokeMethod('createSubWindow', arguments);
651651
}
652+
653+
/// Grabs the keyboard.
654+
Future<bool> grabKeyboard() async {
655+
return await _channel.invokeMethod('grabKeyboard');
656+
}
657+
658+
/// Ungrabs the keyboard.
659+
Future<bool> ungrabKeyboard() async {
660+
return await _channel.invokeMethod('ungrabKeyboard');
661+
}
652662
}
653663

654664
final windowManager = WindowManager.instance;

linux/window_manager_plugin.cc

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct _WindowManagerPlugin {
3535
bool _is_resizing = false;
3636
gchar* title_bar_style_ = strdup("normal");
3737
GdkEventButton _event_button = GdkEventButton{};
38+
GdkDevice* grab_pointer;
3839
};
3940

4041
G_DEFINE_TYPE(WindowManagerPlugin, window_manager_plugin, g_object_get_type())
@@ -443,11 +444,11 @@ static FlMethodResponse* set_skip_taskbar(WindowManagerPlugin* self,
443444
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
444445
}
445446

446-
static FlMethodResponse* set_icon(WindowManagerPlugin* self,
447-
FlValue* args) {
447+
static FlMethodResponse* set_icon(WindowManagerPlugin* self, FlValue* args) {
448448
const gchar* file_name =
449449
fl_value_get_string(fl_value_lookup_string(args, "iconPath"));
450-
const gboolean gtk_result = gtk_window_set_icon_from_file(get_window(self), file_name, NULL);
450+
const gboolean gtk_result =
451+
gtk_window_set_icon_from_file(get_window(self), file_name, NULL);
451452
g_autoptr(FlValue) result = fl_value_new_bool(gtk_result);
452453
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
453454
}
@@ -572,6 +573,89 @@ static FlMethodResponse* start_resizing(WindowManagerPlugin* self,
572573
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
573574
}
574575

576+
static const gchar* gdk_grab_status_code(GdkGrabStatus status) {
577+
switch (status) {
578+
case GDK_GRAB_SUCCESS:
579+
return "GDK_GRAB_SUCCESS";
580+
case GDK_GRAB_ALREADY_GRABBED:
581+
return "GDK_GRAB_ALREADY_GRABBED";
582+
case GDK_GRAB_INVALID_TIME:
583+
return "GDK_GRAB_INVALID_TIME";
584+
case GDK_GRAB_NOT_VIEWABLE:
585+
return "GDK_GRAB_NOT_VIEWABLE";
586+
case GDK_GRAB_FROZEN:
587+
return "GDK_GRAB_FROZEN";
588+
case GDK_GRAB_FAILED:
589+
return "GDK_GRAB_FAILED";
590+
default:
591+
return "GDK_GRAB_???";
592+
}
593+
}
594+
595+
static const gchar* gdk_grab_status_message(GdkGrabStatus status) {
596+
switch (status) {
597+
case GDK_GRAB_SUCCESS:
598+
return "The resource was successfully grabbed.";
599+
case GDK_GRAB_ALREADY_GRABBED:
600+
return "The resource is actively grabbed by another client.";
601+
case GDK_GRAB_INVALID_TIME:
602+
return "The resource was grabbed more recently than the specified time.";
603+
case GDK_GRAB_NOT_VIEWABLE:
604+
return "The grab window or the confine_to window are not viewable.";
605+
case GDK_GRAB_FROZEN:
606+
return "The resource is frozen by an active grab of another client.";
607+
case GDK_GRAB_FAILED:
608+
return "The grab failed for some other reason.";
609+
default:
610+
return "The grab status is unknown.";
611+
}
612+
}
613+
614+
static GdkGrabStatus gdk_grab_keyboard(WindowManagerPlugin* self) {
615+
g_return_val_if_fail(self->grab_pointer == nullptr, GDK_GRAB_FAILED);
616+
617+
auto window = get_window(self);
618+
auto screen = gtk_window_get_screen(window);
619+
auto display = gdk_screen_get_display(screen);
620+
auto seat = gdk_display_get_default_seat(display);
621+
auto gdk_window = get_gdk_window(self);
622+
623+
GdkGrabStatus status = gdk_seat_grab(
624+
seat, gdk_window, GDK_SEAT_CAPABILITY_KEYBOARD, false /* owner_events */,
625+
nullptr /* cursor */, nullptr /* event */, nullptr /*prepare_func */,
626+
nullptr /* prepare_func_data */);
627+
628+
self->grab_pointer = gdk_seat_get_keyboard(seat);
629+
if (!self->grab_pointer) {
630+
self->grab_pointer = gdk_seat_get_pointer(seat);
631+
}
632+
633+
return status;
634+
}
635+
636+
static FlMethodResponse* grab_keyboard(WindowManagerPlugin* self) {
637+
GdkGrabStatus status = gdk_grab_keyboard(self);
638+
639+
if (status != GDK_GRAB_SUCCESS) {
640+
return FL_METHOD_RESPONSE(
641+
fl_method_error_response_new(gdk_grab_status_code(status),
642+
gdk_grab_status_message(status), nullptr));
643+
}
644+
645+
g_autoptr(FlValue) result = fl_value_new_bool(true);
646+
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
647+
}
648+
649+
static FlMethodResponse* ungrab_keyboard(WindowManagerPlugin* self) {
650+
if (self->grab_pointer != nullptr) {
651+
gdk_seat_ungrab(gdk_device_get_seat(self->grab_pointer));
652+
self->grab_pointer = nullptr;
653+
}
654+
655+
g_autoptr(FlValue) result = fl_value_new_bool(true);
656+
return FL_METHOD_RESPONSE(fl_method_success_response_new(result));
657+
}
658+
575659
// Called when a method call is received from Flutter.
576660
static void window_manager_plugin_handle_method_call(
577661
WindowManagerPlugin* self,
@@ -677,6 +761,10 @@ static void window_manager_plugin_handle_method_call(
677761
response = start_dragging(self);
678762
} else if (strcmp(method, "startResizing") == 0) {
679763
response = start_resizing(self, args);
764+
} else if (strcmp(method, "grabKeyboard") == 0) {
765+
response = grab_keyboard(self);
766+
} else if (strcmp(method, "ungrabKeyboard") == 0) {
767+
response = ungrab_keyboard(self);
680768
} else {
681769
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
682770
}

0 commit comments

Comments
 (0)