From 7df4e2454f57b7b876174f6742855596184d4f6c Mon Sep 17 00:00:00 2001 From: craff Date: Sat, 2 Jan 2021 11:03:53 -0900 Subject: [PATCH 1/2] Cleaning and completing callback interface --- examples/maze/maze.ml | 12 +++ lib/egl.ml | 50 ++++++++++ lib/egl.mli | 101 ++++++++++++++------ lib/ml_egl.c | 212 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 341 insertions(+), 34 deletions(-) diff --git a/examples/maze/maze.ml b/examples/maze/maze.ml index 42d8bcf..15fbd8e 100644 --- a/examples/maze/maze.ml +++ b/examples/maze/maze.ml @@ -341,6 +341,18 @@ let _ = in Egl.set_key_release_callback handle_key_release +let _ = + let handle_leave_window ~state ~x ~y = + camera.r_speed <- 0.0; + camera.r_speed <- 0.0; + camera.t_speed <- 0.0; + camera.t_speed <- 0.0; + camera.u_speed <- 0.0; + camera.u_speed <- 0.0; + camera.speed <- 0.0 + in + Egl.set_leave_window_callback handle_leave_window + (* Drawing function for the cube (depending on window ratio and time). *) let draw_maze : float -> unit = fun ratio -> let (<*>) = Matrix.mul in diff --git a/lib/egl.ml b/lib/egl.ml index 963e8a1..86eba64 100644 --- a/lib/egl.ml +++ b/lib/egl.ml @@ -106,25 +106,75 @@ external unset_idle_callback : unit -> unit external set_reshape_callback : (width:int -> height:int -> unit) -> unit = "ml_egl_set_reshape_callback" +external unset_reshape_callback : unit -> unit + = "ml_egl_unset_reshape_callback" + external set_delete_callback : (unit -> unit) -> unit = "ml_egl_set_delete_callback" +external unset_delete_callback : unit -> unit + = "ml_egl_unset_delete_callback" + external set_key_press_callback : (key:keysym -> state:int -> x:int -> y:int -> unit) -> unit = "ml_egl_set_key_press_callback" +external unset_key_press_callback + : unit -> unit + = "ml_egl_unset_key_press_callback" + external set_key_release_callback : (key:keysym -> state:int -> x:int -> y:int -> unit) -> unit = "ml_egl_set_key_release_callback" +external unset_key_release_callback + : unit -> unit + = "ml_egl_unset_key_release_callback" + external set_button_press_callback : (button:button -> state:int -> x:int -> y:int -> unit) -> unit = "ml_egl_set_button_press_callback" +external unset_button_press_callback + : unit -> unit + = "ml_egl_unset_button_press_callback" + external set_button_release_callback : (button:button -> state:int -> x:int -> y:int -> unit) -> unit = "ml_egl_set_button_release_callback" +external unset_button_release_callback + : unit -> unit + = "ml_egl_unset_button_release_callback" + external set_motion_notify_callback : (state:int -> x:int -> y:int -> unit) -> unit = "ml_egl_set_motion_notify_callback" + +external unset_motion_notify_callback + : unit -> unit + = "ml_egl_unset_motion_notify_callback" + +external set_enter_window_callback + : (state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_enter_window_callback" + +external unset_enter_window_callback + : unit -> unit + = "ml_egl_unset_enter_window_callback" + +external set_leave_window_callback + : (state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_leave_window_callback" + +external unset_leave_window_callback + : unit -> unit + = "ml_egl_unset_leave_window_callback" + +external set_change_focus_callback + : (bool -> unit) -> unit + = "ml_egl_set_change_focus_callback" + +external unset_change_focus_callback + : unit -> unit + = "ml_egl_unset_change_focus_callback" diff --git a/lib/egl.mli b/lib/egl.mli index 9211d86..63e8e05 100644 --- a/lib/egl.mli +++ b/lib/egl.mli @@ -94,38 +94,85 @@ external exit_loop : unit -> unit = "ml_egl_exit_loop" (** {b SETTING CALLBACKS} *) (****************************************************************************) -external set_idle_callback : - (unit -> unit) -> unit - = "ml_egl_set_idle_callback" -external unset_idle_callback : - unit -> unit - = "ml_egl_unset_idle_callback" +external set_idle_callback : (unit -> unit) -> unit + = "ml_egl_set_idle_callback" -external set_reshape_callback : - (width:int -> height:int -> unit) -> unit - = "ml_egl_set_reshape_callback" +external unset_idle_callback : unit -> unit + = "ml_egl_unset_idle_callback" -external set_delete_callback : - (unit -> unit) -> unit - = "ml_egl_set_delete_callback" +external set_reshape_callback : (width:int -> height:int -> unit) -> unit + = "ml_egl_set_reshape_callback" -external set_key_press_callback : - (key:keysym -> state:int -> x:int -> y:int -> unit) -> unit - = "ml_egl_set_key_press_callback" +external unset_reshape_callback : unit -> unit + = "ml_egl_unset_reshape_callback" -external set_key_release_callback : - (key:keysym -> state:int -> x:int -> y:int -> unit) -> unit - = "ml_egl_set_key_release_callback" +external set_delete_callback : (unit -> unit) -> unit + = "ml_egl_set_delete_callback" -external set_button_press_callback : - (button:button -> state:int -> x:int -> y:int -> unit) -> unit - = "ml_egl_set_button_press_callback" +external unset_delete_callback : unit -> unit + = "ml_egl_unset_delete_callback" -external set_button_release_callback : - (button:button -> state:int -> x:int -> y:int -> unit) -> unit - = "ml_egl_set_button_release_callback" +external set_key_press_callback + : (key:keysym -> state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_key_press_callback" -external set_motion_notify_callback : - (state:int -> x:int -> y:int -> unit) -> unit - = "ml_egl_set_motion_notify_callback" +external unset_key_press_callback + : unit -> unit + = "ml_egl_unset_key_press_callback" + +external set_key_release_callback + : (key:keysym -> state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_key_release_callback" + +external unset_key_release_callback + : unit -> unit + = "ml_egl_unset_key_release_callback" + +external set_button_press_callback + : (button:button -> state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_button_press_callback" + +external unset_button_press_callback + : unit -> unit + = "ml_egl_unset_button_press_callback" + +external set_button_release_callback + : (button:button -> state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_button_release_callback" + +external unset_button_release_callback + : unit -> unit + = "ml_egl_unset_button_release_callback" + +external set_motion_notify_callback + : (state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_motion_notify_callback" + +external unset_motion_notify_callback + : unit -> unit + = "ml_egl_unset_motion_notify_callback" + +external set_enter_window_callback + : (state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_enter_window_callback" + +external unset_enter_window_callback + : unit -> unit + = "ml_egl_unset_enter_window_callback" + +external set_leave_window_callback + : (state:int -> x:int -> y:int -> unit) -> unit + = "ml_egl_set_leave_window_callback" + +external unset_leave_window_callback + : unit -> unit + = "ml_egl_unset_leave_window_callback" + +external set_change_focus_callback + : (bool -> unit) -> unit + = "ml_egl_set_change_focus_callback" + +external unset_change_focus_callback + : unit -> unit + = "ml_egl_unset_change_focus_callback" diff --git a/lib/ml_egl.c b/lib/ml_egl.c index 9f4b87f..61292c7 100644 --- a/lib/ml_egl.c +++ b/lib/ml_egl.c @@ -50,6 +50,7 @@ static int main_loop_continue = 0 ; /* Callbacks */ +long XEventMask = StructureNotifyMask; // Always have this, to always receive delete static value default_callback = Val_unit ; static value idle_callback = Val_unit ; static value reshape_callback = Val_unit ; @@ -59,6 +60,9 @@ static value key_release_callback = Val_unit ; static value button_press_callback = Val_unit ; static value button_release_callback = Val_unit ; static value motion_notify_callback = Val_unit ; +static value enter_window_callback = Val_unit ; +static value leave_window_callback = Val_unit ; +static value change_focus_callback = Val_unit ; /*** Callback utilities ***/ @@ -146,6 +150,9 @@ static int IOErrorHandler(Display *dpy) caml_modify_generational_global_root(&button_press_callback, default_callback) ; caml_modify_generational_global_root(&button_release_callback, default_callback) ; caml_modify_generational_global_root(&motion_notify_callback, default_callback) ; + caml_modify_generational_global_root(&enter_window_callback, default_callback) ; + caml_modify_generational_global_root(&leave_window_callback, default_callback) ; + caml_modify_generational_global_root(&change_focus_callback, default_callback) ; context = EGL_NO_CONTEXT ; surface = EGL_NO_SURFACE ; @@ -244,9 +251,7 @@ CAMLprim value ml_egl_initialize(value vf, value vc, value vw, value vh, value v 0, 0, width, height, 0, 0, 0) ; if(xwindow == None) init_fail("cannot create X window") ; - XSelectInput(xdisplay, xwindow, - StructureNotifyMask|KeyPressMask|KeyReleaseMask| - ButtonPressMask|ButtonReleaseMask|PointerMotionMask) ; + XSelectInput(xdisplay, xwindow, XEventMask); XMapWindow(xdisplay, xwindow) ; XStoreName(xdisplay, xwindow, String_val(vn)) ; @@ -325,6 +330,9 @@ CAMLprim value ml_egl_initialize(value vf, value vc, value vw, value vh, value v caml_register_generational_global_root(&button_press_callback) ; caml_register_generational_global_root(&button_release_callback) ; caml_register_generational_global_root(&motion_notify_callback) ; + caml_register_generational_global_root(&enter_window_callback) ; + caml_register_generational_global_root(&leave_window_callback) ; + caml_register_generational_global_root(&change_focus_callback) ; initialized = 1 ; @@ -346,9 +354,11 @@ void ml_egl_set_idle_callback(value v) void ml_egl_unset_idle_callback() { + CAMLparam0() ; if(!initialized) - failwith("Egl.set_idle_callback: not initialized") ; + failwith("Egl.unset_idle_callback: not initialized") ; caml_modify_generational_global_root(&idle_callback, default_callback) ; + CAMLreturn0; } void ml_egl_set_reshape_callback(value v) @@ -360,6 +370,15 @@ void ml_egl_set_reshape_callback(value v) CAMLreturn0 ; } +void ml_egl_unset_reshape_callback(value v) +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_reshape_callback: not initialized") ; + caml_modify_generational_global_root(&reshape_callback, default_callback) ; + CAMLreturn0 ; +} + void ml_egl_set_delete_callback(value v) { CAMLparam1(v) ; @@ -369,12 +388,34 @@ void ml_egl_set_delete_callback(value v) CAMLreturn0 ; } +void ml_egl_unset_delete_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_delete_callback: not initialized") ; + caml_modify_generational_global_root(&delete_callback, default_callback) ; + CAMLreturn0 ; +} + void ml_egl_set_key_press_callback(value v) { CAMLparam1(v) ; if(!initialized) failwith("Egl.set_key_press_callback: not initialized") ; caml_modify_generational_global_root(&key_press_callback, v) ; + XEventMask = XEventMask | KeyPressMask; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_key_press_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_key_press_callback: not initialized") ; + caml_modify_generational_global_root(&key_press_callback, default_callback) ; + XEventMask = XEventMask & ~KeyPressMask; + XSelectInput(xdisplay, xwindow, XEventMask); CAMLreturn0 ; } @@ -384,6 +425,19 @@ void ml_egl_set_key_release_callback(value v) if(!initialized) failwith("Egl.set_key_release_callback: not initialized") ; caml_modify_generational_global_root(&key_release_callback, v) ; + XEventMask = XEventMask | KeyReleaseMask; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_key_release_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_key_release_callback: not initialized") ; + caml_modify_generational_global_root(&key_release_callback, default_callback) ; + XEventMask = XEventMask & ~KeyReleaseMask; + XSelectInput(xdisplay, xwindow, XEventMask); CAMLreturn0 ; } @@ -393,6 +447,19 @@ void ml_egl_set_button_press_callback(value v) if(!initialized) failwith("Egl.set_button_press_callback: not initialized") ; caml_modify_generational_global_root(&button_press_callback, v) ; + XEventMask = XEventMask | ButtonPressMask; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_button_press_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_button_press_callback: not initialized") ; + caml_modify_generational_global_root(&button_press_callback, default_callback) ; + XEventMask = XEventMask & ~ButtonPressMask; + XSelectInput(xdisplay, xwindow, XEventMask); CAMLreturn0 ; } @@ -402,6 +469,19 @@ void ml_egl_set_button_release_callback(value v) if(!initialized) failwith("Egl.set_button_release_callback: not initialized") ; caml_modify_generational_global_root(&button_release_callback, v) ; + XEventMask = XEventMask | ButtonReleaseMask; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_button_release_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_button_release_callback: not initialized") ; + caml_modify_generational_global_root(&button_release_callback, default_callback) ; + XEventMask = XEventMask & ~ButtonReleaseMask; + XSelectInput(xdisplay, xwindow, XEventMask); CAMLreturn0 ; } @@ -411,6 +491,85 @@ void ml_egl_set_motion_notify_callback(value v) if(!initialized) failwith("Egl.set_motion_notify_callback: not initialized") ; caml_modify_generational_global_root(&motion_notify_callback, v) ; + XEventMask = XEventMask | PointerMotionMask ; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_motion_notify_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_motion_notify_callback: not initialized") ; + caml_modify_generational_global_root(&motion_notify_callback, default_callback) ; + XEventMask = XEventMask & ~PointerMotionMask ; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_set_enter_window_callback(value v) +{ + CAMLparam1(v) ; + if(!initialized) + failwith("Egl.set_motion_notify_callback: not initialized") ; + caml_modify_generational_global_root(&enter_window_callback, v) ; + XEventMask = XEventMask | EnterWindowMask ; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_enter_window_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_motion_notify_callback: not initialized") ; + caml_modify_generational_global_root(&enter_window_callback, default_callback) ; + XEventMask = XEventMask & ~EnterWindowMask ; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_set_leave_window_callback(value v) +{ + CAMLparam1(v) ; + if(!initialized) + failwith("Egl.set_motion_notify_callback: not initialized") ; + caml_modify_generational_global_root(&leave_window_callback, v) ; + XEventMask = XEventMask | LeaveWindowMask ; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_leave_window_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.unset_motion_notify_callback: not initialized") ; + caml_modify_generational_global_root(&leave_window_callback, default_callback) ; + XEventMask = XEventMask & ~LeaveWindowMask ; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_set_change_focus_callback(value v) +{ + CAMLparam1(v) ; + if(!initialized) + failwith("Egl.set_change_focus_callback: not initialized") ; + caml_modify_generational_global_root(&change_focus_callback, v) ; + XEventMask = XEventMask | FocusChangeMask ; + XSelectInput(xdisplay, xwindow, XEventMask); + CAMLreturn0 ; +} + +void ml_egl_unset_change_focus_callback() +{ + CAMLparam0() ; + if(!initialized) + failwith("Egl.set_change_focus_callback: not initialized") ; + caml_modify_generational_global_root(&change_focus_callback, default_callback) ; + XEventMask = XEventMask & ~FocusChangeMask ; + XSelectInput(xdisplay, xwindow, XEventMask); CAMLreturn0 ; } @@ -515,7 +674,7 @@ void ml_egl_main_loop() button_press_callback != default_callback) { value ml_button = Val_int(event.xbutton.button - Button1); - value ml_state = Val_int(event.xkey.state); + value ml_state = Val_int(event.xbutton.state); value ml_x = Val_int(event.xbutton.x); value ml_y = Val_int(event.xbutton.y); protect_callback4("button press callback", @@ -529,7 +688,7 @@ void ml_egl_main_loop() button_release_callback != default_callback) { value ml_button = Val_int(event.xbutton.button - Button1); - value ml_state = Val_int(event.xkey.state); + value ml_state = Val_int(event.xbutton.state); value ml_x = Val_int(event.xbutton.x); value ml_y = Val_int(event.xbutton.y); protect_callback4("button release callback", @@ -542,7 +701,7 @@ void ml_egl_main_loop() event.xmotion.window == xwindow && motion_notify_callback != default_callback) { - value ml_state = Val_int(event.xkey.state); + value ml_state = Val_int(event.xmotion.state); value ml_x = Val_int(event.xmotion.x); value ml_y = Val_int(event.xmotion.y); @@ -550,6 +709,45 @@ void ml_egl_main_loop() &ml_state, &ml_x, &ml_y); } break ; + case EnterNotify: + if(event.xcrossing.display == xdisplay && + event.xcrossing.window == xwindow && + enter_window_callback != default_callback) + { + value ml_state = Val_int(event.xcrossing.state); + value ml_x = Val_int(event.xcrossing.x); + value ml_y = Val_int(event.xcrossing.y); + + protect_callback3("enter window callback", &enter_window_callback, + &ml_state, &ml_x, &ml_y); + } + break ; + case LeaveNotify: + if(event.xcrossing.display == xdisplay && + event.xcrossing.window == xwindow && + leave_window_callback != default_callback) + { + value ml_state = Val_int(event.xcrossing.state); + value ml_x = Val_int(event.xcrossing.x); + value ml_y = Val_int(event.xcrossing.y); + + protect_callback3("leave window callback", &leave_window_callback, + &ml_state, &ml_x, &ml_y); + } + break ; + case FocusIn: + case FocusOut: + if(event.xfocus.display == xdisplay && + event.xfocus.window == xwindow && + leave_window_callback != default_callback) + { + value ml_in = Val_bool(event.xfocus.type == FocusIn); + + protect_callback("change focus callback", &leave_window_callback, + &ml_in ); + } + break ; + default: break ; } } From 0be0441a2e3b8123e065765796530cdc37547414 Mon Sep 17 00:00:00 2001 From: craff Date: Sat, 9 Jan 2021 18:33:17 -0900 Subject: [PATCH 2/2] typo in error message for uninitialized window when setting unsetting callbacks. --- lib/ml_egl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ml_egl.c b/lib/ml_egl.c index 61292c7..e26c59f 100644 --- a/lib/ml_egl.c +++ b/lib/ml_egl.c @@ -511,7 +511,7 @@ void ml_egl_set_enter_window_callback(value v) { CAMLparam1(v) ; if(!initialized) - failwith("Egl.set_motion_notify_callback: not initialized") ; + failwith("Egl.set_enter_window_callback: not initialized") ; caml_modify_generational_global_root(&enter_window_callback, v) ; XEventMask = XEventMask | EnterWindowMask ; XSelectInput(xdisplay, xwindow, XEventMask); @@ -522,7 +522,7 @@ void ml_egl_unset_enter_window_callback() { CAMLparam0() ; if(!initialized) - failwith("Egl.unset_motion_notify_callback: not initialized") ; + failwith("Egl.unset_enter_window_callback: not initialized") ; caml_modify_generational_global_root(&enter_window_callback, default_callback) ; XEventMask = XEventMask & ~EnterWindowMask ; XSelectInput(xdisplay, xwindow, XEventMask); @@ -533,7 +533,7 @@ void ml_egl_set_leave_window_callback(value v) { CAMLparam1(v) ; if(!initialized) - failwith("Egl.set_motion_notify_callback: not initialized") ; + failwith("Egl.set_leave_window_callback: not initialized") ; caml_modify_generational_global_root(&leave_window_callback, v) ; XEventMask = XEventMask | LeaveWindowMask ; XSelectInput(xdisplay, xwindow, XEventMask); @@ -544,7 +544,7 @@ void ml_egl_unset_leave_window_callback() { CAMLparam0() ; if(!initialized) - failwith("Egl.unset_motion_notify_callback: not initialized") ; + failwith("Egl.unset_leave_window_callback: not initialized") ; caml_modify_generational_global_root(&leave_window_callback, default_callback) ; XEventMask = XEventMask & ~LeaveWindowMask ; XSelectInput(xdisplay, xwindow, XEventMask);