diff --git a/src/java.desktop/unix/classes/sun/awt/wl/WLToolkit.java b/src/java.desktop/unix/classes/sun/awt/wl/WLToolkit.java index e62889c20a22..50271df91a76 100644 --- a/src/java.desktop/unix/classes/sun/awt/wl/WLToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/wl/WLToolkit.java @@ -83,10 +83,10 @@ import java.beans.PropertyChangeListener; import java.lang.reflect.InvocationTargetException; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; @@ -227,7 +227,7 @@ public class WLToolkit extends UNIXToolkit implements Runnable { int result = readEvents(); if (result == READ_RESULT_ERROR) { log.severe("Wayland protocol I/O error"); - // TODO: display disconnect handling here? + shutDownAfterServerError(); break; } else if (result == READ_RESULT_FINISHED_WITH_EVENTS) { AWTAutoShutdown.notifyToolkitThreadBusy(); // busy processing events @@ -249,6 +249,19 @@ public class WLToolkit extends UNIXToolkit implements Runnable { } } } + + private static void shutDownAfterServerError() { + EventQueue.invokeLater(() -> { + var frames = Arrays.asList(Frame.getFrames()); + Collections.reverse(frames); + frames.forEach(frame -> frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING))); + + // They've had their chance to exit from the "window closing" handler code. If we have gotten here, + // that chance wasn't taken. But we cannot continue because the connection with the server is + // no longer available, so let's exit forcibly. + System.exit(0); + }); + } /** * If more than this amount milliseconds has passed since the same mouse button click, diff --git a/src/java.desktop/unix/native/libawt_wlawt/WLClipboard.c b/src/java.desktop/unix/native/libawt_wlawt/WLClipboard.c index 45e82205793c..256216ccc75b 100644 --- a/src/java.desktop/unix/native/libawt_wlawt/WLClipboard.c +++ b/src/java.desktop/unix/native/libawt_wlawt/WLClipboard.c @@ -461,15 +461,30 @@ Java_sun_awt_wl_WLClipboard_initNative( if (payload == NULL) { (*env)->DeleteGlobalRef(env, clipboardGlobalRef); } - CHECK_NULL_THROW_OOME_RETURN(env, payload, "failed to allocate memory for DataOfferPayload", 0); + CHECK_NULL_THROW_OOME_RETURN(env, payload, "Failed to allocate memory for DataOfferPayload", 0); if (!isPrimary) { // TODO: may be needed by DnD also, initialize in a common place wl_data_device = wl_data_device_manager_get_data_device(wl_ddm, wl_seat); + if (wl_data_device == NULL) { + (*env)->DeleteGlobalRef(env, clipboardGlobalRef); + JNU_ThrowByName(env, + "java/awt/AWTError", + "wl_data_device_manager_get_data_device() failed"); + return 0; + } + wl_data_device_add_listener(wl_data_device, &wl_data_device_listener, payload); } else { if (zwp_selection_dm != NULL) { zwp_selection_device = zwp_primary_selection_device_manager_v1_get_device(zwp_selection_dm, wl_seat); + if (zwp_selection_device == NULL) { + (*env)->DeleteGlobalRef(env, clipboardGlobalRef); + JNU_ThrowByName(env, + "java/awt/AWTError", + "zwp_primary_selection_device_manager_v1_get_device() failed"); + return 0; + } zwp_primary_selection_device_v1_add_listener(zwp_selection_device, &zwp_selection_device_listener, payload); } else { (*env)->DeleteGlobalRef(env, clipboardGlobalRef); diff --git a/src/java.desktop/unix/native/libawt_wlawt/WLComponentPeer.c b/src/java.desktop/unix/native/libawt_wlawt/WLComponentPeer.c index d3a4994f9196..5dbdd80af2ee 100644 --- a/src/java.desktop/unix/native/libawt_wlawt/WLComponentPeer.c +++ b/src/java.desktop/unix/native/libawt_wlawt/WLComponentPeer.c @@ -50,10 +50,12 @@ struct activation_token_list_item { struct activation_token_list_item *next_item; }; -static struct activation_token_list_item *add_token(struct activation_token_list_item *list, - struct xdg_activation_token_v1 *token_to_add) { +static struct activation_token_list_item *add_token(JNIEnv* env, + struct activation_token_list_item *list, + struct xdg_activation_token_v1* token_to_add) { struct activation_token_list_item *new_item = (struct activation_token_list_item *) calloc(1, sizeof(struct activation_token_list_item)); + CHECK_NULL_THROW_OOME_RETURN(env, new_item, "Failed to allocate a Wayland activation token", NULL); new_item->token = token_to_add; new_item->next_item = list; return new_item; @@ -119,7 +121,7 @@ xdg_surface_configure(void *data, if (wlFrame->configuredPending) { wlFrame->configuredPending = JNI_FALSE; - + JNIEnv *env = getEnv(); const jobject nativeFramePeer = (*env)->NewLocalRef(env, wlFrame->nativeFramePeer); if (nativeFramePeer) { @@ -430,15 +432,19 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWLSurface struct WLFrame *parentFrame = jlong_to_ptr(parentPtr); if (frame->wl_surface) return; frame->wl_surface = wl_compositor_create_surface(wl_compositor); + CHECK_NULL(frame->wl_surface); frame->xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, frame->wl_surface); + CHECK_NULL(frame->xdg_surface); if (gtk_shell1 != NULL) { frame->gtk_surface = gtk_shell1_get_gtk_surface(gtk_shell1, frame->wl_surface); + CHECK_NULL(frame->gtk_surface); } wl_surface_add_listener(frame->wl_surface, &wl_surface_listener, frame); xdg_surface_add_listener(frame->xdg_surface, &xdg_surface_listener, frame); frame->toplevel = JNI_TRUE; frame->xdg_toplevel = xdg_surface_get_toplevel(frame->xdg_surface); + CHECK_NULL(frame->xdg_toplevel); xdg_toplevel_add_listener(frame->xdg_toplevel, &xdg_toplevel_listener, frame); if (title) { FrameSetTitle(env, frame, title); @@ -472,6 +478,7 @@ newPositioner jint width, jint height, jint offsetX, jint offsetY) { struct xdg_positioner *xdg_positioner = xdg_wm_base_create_positioner(xdg_wm_base); + CHECK_NULL_RETURN(xdg_positioner, NULL); // "For an xdg_positioner object to be considered complete, it must have // a non-zero size set by set_size, and a non-zero anchor rectangle @@ -498,7 +505,9 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWLPopup struct WLFrame *parentFrame = (struct WLFrame*) parentPtr; if (frame->wl_surface) return; frame->wl_surface = wl_compositor_create_surface(wl_compositor); + CHECK_NULL(frame->wl_surface); frame->xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, frame->wl_surface); + CHECK_NULL(frame->xdg_surface); wl_surface_add_listener(frame->wl_surface, &wl_surface_listener, frame); xdg_surface_add_listener(frame->xdg_surface, &xdg_surface_listener, frame); @@ -507,7 +516,9 @@ Java_sun_awt_wl_WLComponentPeer_nativeCreateWLPopup assert(parentFrame); struct xdg_positioner *xdg_positioner = newPositioner(parentX, parentY, parentWidth, parentHeight, width, height, offsetX, offsetY); + CHECK_NULL(xdg_positioner); frame->xdg_popup = xdg_surface_get_popup(frame->xdg_surface, parentFrame->xdg_surface, xdg_positioner); + CHECK_NULL(frame->xdg_popup); xdg_popup_add_listener(frame->xdg_popup, &xdg_popup_listener, frame); xdg_positioner_destroy(xdg_positioner); @@ -530,6 +541,7 @@ Java_sun_awt_wl_WLComponentPeer_nativeRepositionWLPopup struct xdg_positioner *xdg_positioner = newPositioner(parentX, parentY, parentWidth, parentHeight, width, height, offsetX, offsetY); + CHECK_NULL(xdg_positioner); static int token = 42; // This will be received by xdg_popup_repositioned(); unused for now. xdg_popup_reposition(frame->xdg_popup, xdg_positioner, token++); xdg_positioner_destroy(xdg_positioner); @@ -599,7 +611,7 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeStartResize (JNIEnv *env, jobject obj, jlong ptr, jint edges) { struct WLFrame *frame = jlong_to_ptr(ptr); - if (frame->toplevel && wl_seat) { + if (frame->toplevel && wl_seat && frame->xdg_toplevel != NULL) { xdg_toplevel_resize(frame->xdg_toplevel, wl_seat, last_mouse_pressed_serial, edges); } } @@ -647,12 +659,13 @@ Java_sun_awt_wl_WLComponentPeer_nativeActivate struct WLFrame *frame = jlong_to_ptr(ptr); if (frame->wl_surface && xdg_activation_v1 && wl_seat) { struct xdg_activation_token_v1 *token = xdg_activation_v1_get_activation_token(xdg_activation_v1); + CHECK_NULL(token); xdg_activation_token_v1_add_listener(token, &xdg_activation_token_v1_listener, frame); xdg_activation_token_v1_set_serial(token, last_input_or_focus_serial, wl_seat); if (wl_surface_in_focus) { xdg_activation_token_v1_set_surface(token, wl_surface_in_focus); } xdg_activation_token_v1_commit(token); - frame->activation_token_list = add_token(frame->activation_token_list, token); + frame->activation_token_list = add_token(env, frame->activation_token_list, token); } } diff --git a/src/java.desktop/unix/native/libawt_wlawt/WLCursor.c b/src/java.desktop/unix/native/libawt_wlawt/WLCursor.c index 8c38964cb3eb..805dff2af579 100644 --- a/src/java.desktop/unix/native/libawt_wlawt/WLCursor.c +++ b/src/java.desktop/unix/native/libawt_wlawt/WLCursor.c @@ -117,6 +117,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_wl_WLCustomCursor_nativeCreateCustomCursor struct WLCursor *cursor = (struct WLCursor*) malloc(sizeof(struct WLCursor)); if (!cursor) { + JNU_ThrowOutOfMemoryError(env, "Failed to allocate WLCursor"); wl_buffer_destroy(buffer); return 0; } @@ -156,6 +157,7 @@ JNIEXPORT void JNICALL Java_sun_awt_wl_WLComponentPeer_nativeSetCursor if (!wl_cursor_surface) wl_cursor_surface = wl_compositor_create_surface(wl_compositor); + CHECK_NULL(wl_cursor_surface); if (buffer != last_buffer) { last_buffer = buffer; wl_surface_attach(wl_cursor_surface, buffer, 0, 0); diff --git a/src/java.desktop/unix/native/libawt_wlawt/WLGraphicsEnvironment.c b/src/java.desktop/unix/native/libawt_wlawt/WLGraphicsEnvironment.c index 72b7947173ee..4d8a361352a4 100644 --- a/src/java.desktop/unix/native/libawt_wlawt/WLGraphicsEnvironment.c +++ b/src/java.desktop/unix/native/libawt_wlawt/WLGraphicsEnvironment.c @@ -211,11 +211,15 @@ void WLOutputRegister(struct wl_registry *wl_registry, uint32_t id) { WLOutput * output = calloc(1, sizeof(WLOutput)); + JNIEnv * env = getEnv(); + CHECK_NULL_THROW_OOME(env, output, "Failed to allocate WLOutput"); output->id = id; output->wl_output = wl_registry_bind(wl_registry, id, &wl_output_interface, 2); + if (output->wl_output == NULL) { + JNU_ThrowByName(env, "java/awt/AWTError", "wl_registry_bind() failed"); + } wl_output_add_listener(output->wl_output, &wl_output_listener, output); - output->next = outputList; outputList = output; } diff --git a/src/java.desktop/unix/native/libawt_wlawt/WLToolkit.c b/src/java.desktop/unix/native/libawt_wlawt/WLToolkit.c index 23bfaaa43df7..950548390ec5 100644 --- a/src/java.desktop/unix/native/libawt_wlawt/WLToolkit.c +++ b/src/java.desktop/unix/native/libawt_wlawt/WLToolkit.c @@ -658,6 +658,8 @@ process_new_listener_before_end_of_init() { // are delivered in-order, this can be used as a barrier to ensure all previous // requests and the resulting events have been handled." struct wl_callback *callback = wl_display_sync(wl_display); + if (callback == NULL) return; + wl_callback_add_listener(callback, &display_sync_listener, callback); @@ -679,12 +681,16 @@ registry_global(void *data, struct wl_registry *wl_registry, wl_compositor = wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4); } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { xdg_wm_base = wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 3); - xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL); - process_new_listener_before_end_of_init(); + if (xdg_wm_base != NULL) { + xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL); + process_new_listener_before_end_of_init(); + } } else if (strcmp(interface, wl_seat_interface.name) == 0) { wl_seat = wl_registry_bind(wl_registry, name, &wl_seat_interface, 5); - wl_seat_add_listener(wl_seat, &wl_seat_listener, NULL); - process_new_listener_before_end_of_init(); + if (wl_seat != NULL) { + wl_seat_add_listener(wl_seat, &wl_seat_listener, NULL); + process_new_listener_before_end_of_init(); + } } else if (strcmp(interface, wl_output_interface.name) == 0) { WLOutputRegister(wl_registry, name); process_new_listener_before_end_of_init(); @@ -695,23 +701,25 @@ registry_global(void *data, struct wl_registry *wl_registry, } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) { wl_ddm = wl_registry_bind(wl_registry, name,&wl_data_device_manager_interface, 3); } else if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) { - zwp_selection_dm = wl_registry_bind(wl_registry, name,&zwp_primary_selection_device_manager_v1_interface, 1); + zwp_selection_dm = wl_registry_bind(wl_registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); } #ifdef WAKEFIELD_ROBOT else if (strcmp(interface, wakefield_interface.name) == 0) { wakefield = wl_registry_bind(wl_registry, name, &wakefield_interface, 1); - wakefield_add_listener(wakefield, &wakefield_listener, NULL); - robot_queue = wl_display_create_queue(wl_display); - if (robot_queue == NULL) { - J2dTrace(J2D_TRACE_ERROR, "WLToolkit: Failed to create wakefield robot queue\n"); - wakefield_destroy(wakefield); - wakefield = NULL; - } else { - wl_proxy_set_queue((struct wl_proxy*)wakefield, robot_queue); + if (wakefield != NULL) { + wakefield_add_listener(wakefield, &wakefield_listener, NULL); + robot_queue = wl_display_create_queue(wl_display); + if (robot_queue == NULL) { + J2dTrace(J2D_TRACE_ERROR, "WLToolkit: Failed to create wakefield robot queue\n"); + wakefield_destroy(wakefield); + wakefield = NULL; + } else { + wl_proxy_set_queue((struct wl_proxy*)wakefield, robot_queue); + } + // TODO: call before destroying the display: + // wl_event_queue_destroy(robot_queue); } - // TODO: call before destroying the display: - // wl_event_queue_destroy(robot_queue); } #endif } @@ -931,6 +939,11 @@ Java_sun_awt_wl_WLToolkit_initIDs } struct wl_registry *wl_registry = wl_display_get_registry(wl_display); + if (wl_registry == NULL) { + JNU_ThrowByName(env, "java/awt/AWTError", "Failed to obtain Wayland registry"); + return; + } + wl_registry_add_listener(wl_registry, &wl_registry_listener, NULL); // Process info about Wayland globals here; maybe register more handlers that // will have to be processed later in finalize_init().