From 81ebbb2463df8b014bb209dc4028668fc78e8327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 7 Oct 2024 08:28:18 +0000 Subject: [PATCH 01/16] 8341525: G1: use bit clearing to remove tightly-coupled initialization store pre-barriers Reviewed-by: mdoerr, kbarrett, shade, tschatzl --- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 8e17d1d2a7a..4ec7e10cd9a 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -332,7 +332,8 @@ Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) co if (tightly_coupled_alloc) { assert(!use_ReduceInitialCardMarks(), "post-barriers are only needed for tightly-coupled initialization stores when ReduceInitialCardMarks is disabled"); - access.set_barrier_data(access.barrier_data() ^ G1C2BarrierPre); + // Pre-barriers are unnecessary for tightly-coupled initialization stores. + access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre); } } return BarrierSetC2::store_at_resolved(access, val); From 747a3fa31d9a9512475615c91d2ee9c2d2a94e8e Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 7 Oct 2024 08:39:44 +0000 Subject: [PATCH 02/16] 8341562: RISC-V: Generate comments in -XX:+PrintInterpreter to link to source code Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 5 ++-- .../templateInterpreterGenerator_riscv.cpp | 27 ++++++++++++------- src/hotspot/cpu/riscv/templateTable_riscv.cpp | 3 ++- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index 280ae6062a9..f638db9f0bf 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,6 +28,7 @@ #include "asm/macroAssembler.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" +#include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" @@ -37,7 +38,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/stubRoutines.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 1f32488777d..7c811aa3a0c 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -27,6 +27,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "classfile/javaClasses.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeTracer.hpp" @@ -70,7 +71,7 @@ // Max size with JVMTI int TemplateInterpreter::InterpreterCodeSize = 256 * 1024; -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> //----------------------------------------------------------------------------- @@ -1748,13 +1749,21 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& vep) { assert(t != nullptr && t->is_valid() && t->tos_in() == vtos, "illegal template"); Label L; - aep = __ pc(); __ push_ptr(); __ j(L); - fep = __ pc(); __ push_f(); __ j(L); - dep = __ pc(); __ push_d(); __ j(L); - lep = __ pc(); __ push_l(); __ j(L); - bep = cep = sep = - iep = __ pc(); __ push_i(); - vep = __ pc(); + aep = __ pc(); // atos entry point + __ push_ptr(); + __ j(L); + fep = __ pc(); // ftos entry point + __ push_f(); + __ j(L); + dep = __ pc(); // dtos entry point + __ push_d(); + __ j(L); + lep = __ pc(); // ltos entry point + __ push_l(); + __ j(L); + bep = cep = sep = iep = __ pc(); // [bcsi]tos entry point + __ push_i(); + vep = __ pc(); // vtos entry point __ bind(L); generate_and_dispatch(t); } diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 2e6902180a8..2fede262057 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/tlab_globals.hpp" @@ -49,7 +50,7 @@ #include "runtime/synchronizer.hpp" #include "utilities/powerOfTwo.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> // Address computation: local variables From 28977972a0129892543222eada4dc99f4cd62574 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 7 Oct 2024 09:32:40 +0000 Subject: [PATCH 03/16] 8340880: RISC-V: add t3-t6 alias into assemler_riscv.hpp Reviewed-by: luhenry, fyang --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 4 ++++ src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 20 +++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index d1021d9e283..a8675907907 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -143,6 +143,10 @@ constexpr Register x19_sender_sp = x19; // Sender's SP while in interpreter constexpr Register t0 = x5; constexpr Register t1 = x6; constexpr Register t2 = x7; +constexpr Register t3 = x28; +constexpr Register t4 = x29; +constexpr Register t5 = x30; +constexpr Register t6 = x31; const Register g_INTArgReg[Argument::n_int_register_parameters_c] = { c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5, c_rarg6, c_rarg7 diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 8bf3ac5c901..bc2816147a0 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -4482,7 +4482,7 @@ class StubGenerator: public StubCodeGenerator { RegSet reg_cache_saved_regs = RegSet::of(x24, x25, x26, x27); // s8, s9, s10, s11 RegSet reg_cache_regs; reg_cache_regs += reg_cache_saved_regs; - reg_cache_regs += RegSet::of(x28, x29, x30, x31); // t3, t4, t5, t6 + reg_cache_regs += RegSet::of(t3, t4, t5, t6); BufRegCache reg_cache(_masm, reg_cache_regs); RegSet saved_regs; @@ -5462,8 +5462,8 @@ class StubGenerator: public StubCodeGenerator { Register isMIME = c_rarg6; Register codec = c_rarg7; - Register dstBackup = x31; - Register length = x28; // t3, total length of src data in bytes + Register dstBackup = t6; + Register length = t3; // total length of src data in bytes Label ProcessData, Exit; Label ProcessScalar, ScalarLoop; @@ -5498,7 +5498,7 @@ class StubGenerator: public StubCodeGenerator { Register stepSrcM1 = send; Register stepSrcM2 = doff; Register stepDst = isURL; - Register size = x29; // t4 + Register size = t4; __ mv(size, MaxVectorSize * 2); __ mv(stepSrcM1, MaxVectorSize * 4); @@ -5550,7 +5550,7 @@ class StubGenerator: public StubCodeGenerator { // scalar version { Register byte0 = soff, byte1 = send, byte2 = doff, byte3 = isURL; - Register combined32Bits = x29; // t5 + Register combined32Bits = t4; // encoded: [byte0[5:0] : byte1[5:0] : byte2[5:0]] : byte3[5:0]] => // plain: [byte0[5:0]+byte1[5:4] : byte1[3:0]+byte2[5:2] : byte2[1:0]+byte3[5:0]] @@ -5708,10 +5708,10 @@ class StubGenerator: public StubCodeGenerator { Register nmax = c_rarg4; Register base = c_rarg5; Register count = c_rarg6; - Register temp0 = x28; // t3 - Register temp1 = x29; // t4 - Register temp2 = x30; // t5 - Register temp3 = x31; // t6 + Register temp0 = t3; + Register temp1 = t4; + Register temp2 = t5; + Register temp3 = t6; VectorRegister vzero = v31; VectorRegister vbytes = v8; // group: v8, v9, v10, v11 @@ -6102,7 +6102,7 @@ static const int64_t right_3_bits = right_n_bits(3); __ kernel_crc32(crc, buf, len, c_rarg3, c_rarg4, c_rarg5, c_rarg6, // tmp's for tables - c_rarg7, t2, x28, x29, x30, x31); // misc tmps + c_rarg7, t2, t3, t4, t5, t6); // misc tmps __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(); From 520060f79a3cedb8f93e6bbd0e9b2823eaabf79a Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Mon, 7 Oct 2024 12:44:42 +0000 Subject: [PATCH 04/16] 8340799: Add border inside instruction frame in PassFailJFrame Reviewed-by: prr, dnguyen --- .../awt/regtesthelpers/PassFailJFrame.java | 60 +++++++++++++++---- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index feb5da43a5c..9fc3abe4b7d 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -24,6 +24,7 @@ import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Font; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; @@ -69,6 +70,7 @@ import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer; +import javax.swing.border.Border; import javax.swing.text.JTextComponent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; @@ -655,6 +657,8 @@ private static JComponent createInstructionUIPanel(String instructions, boolean addLogArea, int logAreaRows) { JPanel main = new JPanel(new BorderLayout()); + main.setBorder(createFrameBorder()); + timeoutHandlerPanel = new TimeoutHandlerPanel(testTimeOut); main.add(timeoutHandlerPanel, BorderLayout.NORTH); @@ -664,7 +668,7 @@ private static JComponent createInstructionUIPanel(String instructions, text.setEditable(false); JPanel textPanel = new JPanel(new BorderLayout()); - textPanel.setBorder(createEmptyBorder(4, 0, 0, 0)); + textPanel.setBorder(createEmptyBorder(GAP, 0, GAP, 0)); textPanel.add(new JScrollPane(text), BorderLayout.CENTER); main.add(textPanel, BorderLayout.CENTER); @@ -681,7 +685,8 @@ private static JComponent createInstructionUIPanel(String instructions, timeoutHandlerPanel.stop(); }); - JPanel buttonsPanel = new JPanel(); + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, + GAP, 0)); buttonsPanel.add(btnPass); buttonsPanel.add(btnFail); @@ -692,10 +697,12 @@ private static JComponent createInstructionUIPanel(String instructions, if (addLogArea) { logArea = new JTextArea(logAreaRows, columns); logArea.setEditable(false); + logArea.setBorder(createTextBorder()); Box buttonsLogPanel = Box.createVerticalBox(); buttonsLogPanel.add(buttonsPanel); + buttonsLogPanel.add(Box.createVerticalStrut(GAP)); buttonsLogPanel.add(new JScrollPane(logArea)); main.add(buttonsLogPanel, BorderLayout.SOUTH); @@ -713,7 +720,7 @@ private static JTextComponent configurePlainText(String instructions, JTextArea text = new JTextArea(instructions, rows, columns); text.setLineWrap(true); text.setWrapStyleWord(true); - text.setBorder(createEmptyBorder(4, 4, 4, 4)); + text.setBorder(createTextBorder()); return text; } @@ -735,6 +742,29 @@ private static JTextComponent configureHTML(String instructions, return text; } + /** A default gap between components. */ + private static final int GAP = 4; + + /** + * Creates a default border for frames or dialogs. + * It uses the default gap of {@value GAP}. + * + * @return the border for frames and dialogs + */ + private static Border createFrameBorder() { + return createEmptyBorder(GAP, GAP, GAP, GAP); + } + + /** + * Creates a border set to text area. + * It uses the default gap of {@value GAP}. + * + * @return the border for text area + */ + private static Border createTextBorder() { + return createEmptyBorder(GAP, GAP, GAP, GAP); + } + /** * Creates a test UI window. @@ -1086,26 +1116,30 @@ public void awaitAndCheck() throws InterruptedException, InvocationTargetExcepti * Requests the description of the test failure reason from the tester. */ private static void requestFailureReason() { - final JDialog dialog = new JDialog(frame, "Test Failure ", true); - dialog.setTitle("Failure reason"); - JPanel jPanel = new JPanel(new BorderLayout()); - JTextArea jTextArea = new JTextArea(5, 20); + final JDialog dialog = new JDialog(frame, "Failure reason", true); + + JTextArea reason = new JTextArea(5, 20); + reason.setBorder(createTextBorder()); JButton okButton = new JButton("OK"); okButton.addActionListener((ae) -> { - String text = jTextArea.getText(); + String text = reason.getText(); setFailureReason(FAILURE_REASON + (!text.isEmpty() ? text : EMPTY_REASON)); dialog.setVisible(false); }); - jPanel.add(new JScrollPane(jTextArea), BorderLayout.CENTER); - - JPanel okayBtnPanel = new JPanel(); + JPanel okayBtnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, + GAP, 0)); + okayBtnPanel.setBorder(createEmptyBorder(GAP, 0, 0, 0)); okayBtnPanel.add(okButton); - jPanel.add(okayBtnPanel, BorderLayout.SOUTH); - dialog.add(jPanel); + JPanel main = new JPanel(new BorderLayout()); + main.setBorder(createFrameBorder()); + main.add(new JScrollPane(reason), BorderLayout.CENTER); + main.add(okayBtnPanel, BorderLayout.SOUTH); + + dialog.add(main); dialog.setLocationRelativeTo(frame); dialog.pack(); dialog.setVisible(true); From 4ba170c403ae85576f84dafd4a157ba0db99873f Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Mon, 7 Oct 2024 12:45:04 +0000 Subject: [PATCH 05/16] 8341235: Improve default instruction frame title in PassFailJFrame Reviewed-by: prr --- .../awt/regtesthelpers/PassFailJFrame.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 9fc3abe4b7d..41c5fdf8ccd 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -45,6 +45,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -289,9 +290,15 @@ */ public final class PassFailJFrame { - private static final String TITLE = "Test Instruction Frame"; + /** A default title for the instruction frame. */ + private static final String TITLE = "Test Instructions"; + + /** A default test timeout. */ private static final long TEST_TIMEOUT = 5; + + /** A default number of rows for displaying the test instructions. */ private static final int ROWS = 10; + /** A default number of columns for displaying the test instructions. */ private static final int COLUMNS = 40; /** @@ -304,7 +311,7 @@ public final class PassFailJFrame { */ private static final String FAILURE_REASON = "Failure Reason:\n"; /** - * The failure reason message when the user didn't provide one. + * The failure reason message when the user doesn't provide one. */ private static final String EMPTY_REASON = "(no reason provided)"; @@ -1824,9 +1831,41 @@ public PassFailJFrame build() throws InterruptedException, return new PassFailJFrame(this); } + /** + * Returns the file name of the test, if the {@code test.file} property + * is defined, concatenated with {@code " - "} which serves as a prefix + * to the default instruction frame title; + * or an empty string if the {@code test.file} property is not defined. + * + * @return the prefix to the default title: + * either the file name of the test or an empty string + * + * @see jtreg + * test-specific system properties and environment variables + */ + private static String getTestFileNamePrefix() { + String testFile = System.getProperty("test.file"); + if (testFile == null) { + return ""; + } + + return Paths.get(testFile).getFileName().toString() + + " - "; + } + + /** + * Validates the state of the builder and + * expands parameters that have no assigned values + * to their default values. + * + * @throws IllegalStateException if no instructions are provided, + * or if {@code PositionWindows} implementation is + * provided but neither window creator nor + * test window list are set + */ private void validate() { if (title == null) { - title = TITLE; + title = getTestFileNamePrefix() + TITLE; } if (instructions == null || instructions.isEmpty()) { From a2372c607c940589f239d4e59b675d3b2e626fd9 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Mon, 7 Oct 2024 13:26:16 +0000 Subject: [PATCH 06/16] 8341238: G1: Refactor G1Policy to move collection set selection methods into G1CollectionSet Reviewed-by: tschatzl, mli --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 232 ++++++++++++++++++-- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 16 ++ src/hotspot/share/gc/g1/g1Policy.cpp | 213 ------------------ src/hotspot/share/gc/g1/g1Policy.hpp | 24 +- 4 files changed, 236 insertions(+), 249 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index d315497268f..ec90fd37750 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -26,7 +26,7 @@ #include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" -#include "gc/g1/g1CollectionSetCandidates.hpp" +#include "gc/g1/g1CollectionSetCandidates.inline.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" @@ -346,20 +346,16 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { G1CollectionCandidateRegionList pinned_retained_regions; if (collector_state()->in_mixed_phase()) { - time_remaining_ms = _policy->select_candidates_from_marking(&candidates()->marking_regions(), - time_remaining_ms, - &initial_old_regions, - &_optional_old_regions, - &pinned_marking_regions); + time_remaining_ms = select_candidates_from_marking(time_remaining_ms, + &initial_old_regions, + &pinned_marking_regions); } else { log_debug(gc, ergo, cset)("Do not add marking candidates to collection set due to pause type."); } - _policy->select_candidates_from_retained(&candidates()->retained_regions(), - time_remaining_ms, - &initial_old_regions, - &_optional_old_regions, - &pinned_retained_regions); + select_candidates_from_retained(time_remaining_ms, + &initial_old_regions, + &pinned_retained_regions); // Move initially selected old regions to collection set directly. move_candidates_to_collection_set(&initial_old_regions); @@ -394,6 +390,215 @@ void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateReg candidates()->remove(regions); } +static void print_finish_message(const char* reason, bool from_marking) { + log_debug(gc, ergo, cset)("Finish adding %s candidates to collection set (%s).", + from_marking ? "marking" : "retained", reason); +} + +double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions) { + uint num_expensive_regions = 0; + + uint num_initial_regions_selected = 0; + uint num_optional_regions_selected = 0; + uint num_pinned_regions = 0; + + double predicted_initial_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + + double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); + + const uint min_old_cset_length = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length()); + const uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length()); + const uint max_optional_regions = max_old_cset_length - min_old_cset_length; + bool check_time_remaining = _policy->use_adaptive_young_list_length(); + + G1CollectionCandidateList* marking_list = &candidates()->marking_regions(); + assert(marking_list != nullptr, "must be"); + + log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " + "Min %u regions, max %u regions, available %u regions" + "time remaining %1.2fms, optional threshold %1.2fms", + min_old_cset_length, max_old_cset_length, marking_list->length(), time_remaining_ms, optional_threshold_ms); + + G1CollectionCandidateListIterator iter = marking_list->begin(); + for (; iter != marking_list->end(); ++iter) { + if (num_initial_regions_selected + num_optional_regions_selected >= max_old_cset_length) { + // Added maximum number of old regions to the CSet. + print_finish_message("Maximum number of regions reached", true); + break; + } + G1HeapRegion* hr = (*iter)->_r; + // Skip evacuating pinned marking regions because we are not getting any free + // space from them (and we expect to get free space from marking candidates). + // Also prepare to move them to retained regions to be evacuated optionally later + // to not impact the mixed phase too much. + if (hr->has_pinned_objects()) { + num_pinned_regions++; + (*iter)->update_num_unreclaimed(); + log_trace(gc, ergo, cset)("Marking candidate %u can not be reclaimed currently. Skipping.", hr->hrm_index()); + pinned_old_regions->append(hr); + continue; + } + double predicted_time_ms = _policy->predict_region_total_time_ms(hr, false); + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); + // Add regions to old set until we reach the minimum amount + if (initial_old_regions->length() < min_old_cset_length) { + initial_old_regions->append(hr); + num_initial_regions_selected++; + predicted_initial_time_ms += predicted_time_ms; + // Record the number of regions added with no time remaining + if (time_remaining_ms == 0.0) { + num_expensive_regions++; + } + } else if (!check_time_remaining) { + // In the non-auto-tuning case, we'll finish adding regions + // to the CSet if we reach the minimum. + print_finish_message("Region amount reached min", true); + break; + } else { + // Keep adding regions to old set until we reach the optional threshold + if (time_remaining_ms > optional_threshold_ms) { + predicted_initial_time_ms += predicted_time_ms; + initial_old_regions->append(hr); + num_initial_regions_selected++; + } else if (time_remaining_ms > 0) { + // Keep adding optional regions until time is up. + assert(_optional_old_regions.length() < max_optional_regions, "Should not be possible."); + predicted_optional_time_ms += predicted_time_ms; + _optional_old_regions.append(hr); + num_optional_regions_selected++; + } else { + print_finish_message("Predicted time too high", true); + break; + } + } + } + if (iter == marking_list->end()) { + log_debug(gc, ergo, cset)("Marking candidates exhausted."); + } + + if (num_expensive_regions > 0) { + log_debug(gc, ergo, cset)("Added %u marking candidates to collection set although the predicted time was too high.", + num_expensive_regions); + } + + log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u, optional: %u, pinned: %u, " + "predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2fms", + num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, + predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); + + assert(initial_old_regions->length() == num_initial_regions_selected, "must be"); + assert(_optional_old_regions.length() == num_optional_regions_selected, "must be"); + return time_remaining_ms; +} + +void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions) { + uint num_initial_regions_selected = 0; + uint num_optional_regions_selected = 0; + uint num_expensive_regions_selected = 0; + uint num_pinned_regions = 0; + + double predicted_initial_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + + uint const min_regions = _policy->min_retained_old_cset_length(); + // We want to make sure that on the one hand we process the retained regions asap, + // but on the other hand do not take too many of them as optional regions. + // So we split the time budget into budget we will unconditionally take into the + // initial old regions, and budget for taking optional regions from the retained + // list. + double optional_time_remaining_ms = _policy->max_time_for_retaining(); + time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms); + + G1CollectionCandidateList* retained_list = &candidates()->retained_regions(); + + log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " + "Min %u regions, available %u, " + "time remaining %1.2fms, optional remaining %1.2fms", + min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms); + + for (G1CollectionSetCandidateInfo* ci : *retained_list) { + G1HeapRegion* r = ci->_r; + double predicted_time_ms = _policy->predict_region_total_time_ms(r, collector_state()->in_young_only_phase()); + bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms; + // If we can't reclaim that region ignore it for now. + if (r->has_pinned_objects()) { + num_pinned_regions++; + if (ci->update_num_unreclaimed()) { + log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Skipping.", r->hrm_index()); + } else { + log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Dropping.", r->hrm_index()); + pinned_old_regions->append(r); + } + continue; + } + + if (fits_in_remaining_time || (num_expensive_regions_selected < min_regions)) { + predicted_initial_time_ms += predicted_time_ms; + if (!fits_in_remaining_time) { + num_expensive_regions_selected++; + } + initial_old_regions->append(r); + num_initial_regions_selected++; + } else if (predicted_time_ms <= optional_time_remaining_ms) { + predicted_optional_time_ms += predicted_time_ms; + _optional_old_regions.append(r); + num_optional_regions_selected++; + } else { + // Fits neither initial nor optional time limit. Exit. + break; + } + time_remaining_ms = MAX2(0.0, time_remaining_ms - predicted_time_ms); + optional_time_remaining_ms = MAX2(0.0, optional_time_remaining_ms - predicted_time_ms); + } + + uint num_regions_selected = num_initial_regions_selected + num_optional_regions_selected; + if (num_regions_selected == retained_list->length()) { + log_debug(gc, ergo, cset)("Retained candidates exhausted."); + } + if (num_expensive_regions_selected > 0) { + log_debug(gc, ergo, cset)("Added %u retained candidates to collection set although the predicted time was too high.", + num_expensive_regions_selected); + } + + log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, " + "predicted initial time: %1.2fms, predicted optional time: %1.2fms, " + "time remaining: %1.2fms optional time remaining %1.2fms", + num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, + predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms); +} + +void G1CollectionSet::select_candidates_from_optional_regions(double time_remaining_ms, + G1CollectionCandidateRegionList* selected_regions) { + assert(optional_region_length() > 0, + "Should only be called when there are optional regions"); + + double total_prediction_ms = 0.0; + + for (G1HeapRegion* r : _optional_old_regions) { + double prediction_ms = _policy->predict_region_total_time_ms(r, false); + + if (prediction_ms > time_remaining_ms) { + log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", + prediction_ms, r->hrm_index(), time_remaining_ms); + break; + } + // This region will be included in the next optional evacuation. + + total_prediction_ms += prediction_ms; + time_remaining_ms -= prediction_ms; + + selected_regions->append(r); + } + + log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms", + selected_regions->length(), _optional_old_regions.length(), total_prediction_ms); +} + void G1CollectionSet::prepare_optional_regions(G1CollectionCandidateRegionList* regions){ uint cur_index = 0; for (G1HeapRegion* r : *regions) { @@ -441,9 +646,8 @@ bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_ti update_incremental_marker(); G1CollectionCandidateRegionList selected_regions; - _policy->calculate_optional_collection_set_regions(&_optional_old_regions, - remaining_pause_time, - &selected_regions); + select_candidates_from_optional_regions(remaining_pause_time, + &selected_regions); move_candidates_to_collection_set(&selected_regions); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index e569d3ee966..5280ba7d0fd 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -196,6 +196,22 @@ class G1CollectionSet { // and retained collection set candidates. void finalize_old_part(double time_remaining_ms); + // Calculate and fill in the initial, optional and pinned old gen candidate regions from + // the given candidate list and the remaining time. + // Returns the remaining time. + double select_candidates_from_marking(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions); + + void select_candidates_from_retained(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions); + + // Calculate the number of optional regions from the given collection set candidates, + // the remaining time and the maximum number of these regions. + void select_candidates_from_optional_regions(double time_remaining_ms, + G1CollectionCandidateRegionList* selected); + // Iterate the part of the collection set given by the offset and length applying the given // G1HeapRegionClosure. The worker_id will determine where in the part to start the iteration // to allow for more efficient parallel iteration. diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index e7e57c962c7..6d0864f032c 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1467,219 +1467,6 @@ uint G1Policy::calc_max_old_cset_length() const { return (uint)ceil(result); } -static void print_finish_message(const char* reason, bool from_marking) { - log_debug(gc, ergo, cset)("Finish adding %s candidates to collection set (%s).", - from_marking ? "marking" : "retained", reason); -} - -double G1Policy::select_candidates_from_marking(G1CollectionCandidateList* marking_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions) { - assert(marking_list != nullptr, "must be"); - - uint num_expensive_regions = 0; - - uint num_initial_regions_selected = 0; - uint num_optional_regions_selected = 0; - uint num_pinned_regions = 0; - - double predicted_initial_time_ms = 0.0; - double predicted_optional_time_ms = 0.0; - - double optional_threshold_ms = time_remaining_ms * optional_prediction_fraction(); - - const uint min_old_cset_length = calc_min_old_cset_length(candidates()->last_marking_candidates_length()); - const uint max_old_cset_length = MAX2(min_old_cset_length, calc_max_old_cset_length()); - const uint max_optional_regions = max_old_cset_length - min_old_cset_length; - bool check_time_remaining = use_adaptive_young_list_length(); - - log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " - "Min %u regions, max %u regions, available %u regions" - "time remaining %1.2fms, optional threshold %1.2fms", - min_old_cset_length, max_old_cset_length, marking_list->length(), time_remaining_ms, optional_threshold_ms); - - G1CollectionCandidateListIterator iter = marking_list->begin(); - for (; iter != marking_list->end(); ++iter) { - if (num_initial_regions_selected + num_optional_regions_selected >= max_old_cset_length) { - // Added maximum number of old regions to the CSet. - print_finish_message("Maximum number of regions reached", true); - break; - } - G1HeapRegion* hr = (*iter)->_r; - // Skip evacuating pinned marking regions because we are not getting any free - // space from them (and we expect to get free space from marking candidates). - // Also prepare to move them to retained regions to be evacuated optionally later - // to not impact the mixed phase too much. - if (hr->has_pinned_objects()) { - num_pinned_regions++; - (*iter)->update_num_unreclaimed(); - log_trace(gc, ergo, cset)("Marking candidate %u can not be reclaimed currently. Skipping.", hr->hrm_index()); - pinned_old_regions->append(hr); - continue; - } - double predicted_time_ms = predict_region_total_time_ms(hr, false); - time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); - // Add regions to old set until we reach the minimum amount - if (initial_old_regions->length() < min_old_cset_length) { - initial_old_regions->append(hr); - num_initial_regions_selected++; - predicted_initial_time_ms += predicted_time_ms; - // Record the number of regions added with no time remaining - if (time_remaining_ms == 0.0) { - num_expensive_regions++; - } - } else if (!check_time_remaining) { - // In the non-auto-tuning case, we'll finish adding regions - // to the CSet if we reach the minimum. - print_finish_message("Region amount reached min", true); - break; - } else { - // Keep adding regions to old set until we reach the optional threshold - if (time_remaining_ms > optional_threshold_ms) { - predicted_initial_time_ms += predicted_time_ms; - initial_old_regions->append(hr); - num_initial_regions_selected++; - } else if (time_remaining_ms > 0) { - // Keep adding optional regions until time is up. - assert(optional_old_regions->length() < max_optional_regions, "Should not be possible."); - predicted_optional_time_ms += predicted_time_ms; - optional_old_regions->append(hr); - num_optional_regions_selected++; - } else { - print_finish_message("Predicted time too high", true); - break; - } - } - } - if (iter == marking_list->end()) { - log_debug(gc, ergo, cset)("Marking candidates exhausted."); - } - - if (num_expensive_regions > 0) { - log_debug(gc, ergo, cset)("Added %u marking candidates to collection set although the predicted time was too high.", - num_expensive_regions); - } - - log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u, optional: %u, pinned: %u, " - "predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2fms", - num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, - predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); - - assert(initial_old_regions->length() == num_initial_regions_selected, "must be"); - assert(optional_old_regions->length() == num_optional_regions_selected, "must be"); - return time_remaining_ms; -} - -void G1Policy::select_candidates_from_retained(G1CollectionCandidateList* retained_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions) { - - uint const min_regions = min_retained_old_cset_length(); - - uint num_initial_regions_selected = 0; - uint num_optional_regions_selected = 0; - uint num_expensive_regions_selected = 0; - uint num_pinned_regions = 0; - - double predicted_initial_time_ms = 0.0; - double predicted_optional_time_ms = 0.0; - - // We want to make sure that on the one hand we process the retained regions asap, - // but on the other hand do not take too many of them as optional regions. - // So we split the time budget into budget we will unconditionally take into the - // initial old regions, and budget for taking optional regions from the retained - // list. - double optional_time_remaining_ms = max_time_for_retaining(); - time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms); - - log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " - "Min %u regions, available %u, " - "time remaining %1.2fms, optional remaining %1.2fms", - min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms); - - for (G1CollectionSetCandidateInfo* ci : *retained_list) { - G1HeapRegion* r = ci->_r; - double predicted_time_ms = predict_region_total_time_ms(r, collector_state()->in_young_only_phase()); - bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms; - // If we can't reclaim that region ignore it for now. - if (r->has_pinned_objects()) { - num_pinned_regions++; - if (ci->update_num_unreclaimed()) { - log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Skipping.", r->hrm_index()); - } else { - log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Dropping.", r->hrm_index()); - pinned_old_regions->append(r); - } - continue; - } - - if (fits_in_remaining_time || (num_expensive_regions_selected < min_regions)) { - predicted_initial_time_ms += predicted_time_ms; - if (!fits_in_remaining_time) { - num_expensive_regions_selected++; - } - initial_old_regions->append(r); - num_initial_regions_selected++; - } else if (predicted_time_ms <= optional_time_remaining_ms) { - predicted_optional_time_ms += predicted_time_ms; - optional_old_regions->append(r); - num_optional_regions_selected++; - } else { - // Fits neither initial nor optional time limit. Exit. - break; - } - time_remaining_ms = MAX2(0.0, time_remaining_ms - predicted_time_ms); - optional_time_remaining_ms = MAX2(0.0, optional_time_remaining_ms - predicted_time_ms); - } - - uint num_regions_selected = num_initial_regions_selected + num_optional_regions_selected; - if (num_regions_selected == retained_list->length()) { - log_debug(gc, ergo, cset)("Retained candidates exhausted."); - } - if (num_expensive_regions_selected > 0) { - log_debug(gc, ergo, cset)("Added %u retained candidates to collection set although the predicted time was too high.", - num_expensive_regions_selected); - } - - log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, " - "predicted initial time: %1.2fms, predicted optional time: %1.2fms, " - "time remaining: %1.2fms optional time remaining %1.2fms", - num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, - predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms); -} - -void G1Policy::calculate_optional_collection_set_regions(G1CollectionCandidateRegionList* optional_regions, - double time_remaining_ms, - G1CollectionCandidateRegionList* selected_regions) { - assert(_collection_set->optional_region_length() > 0, - "Should only be called when there are optional regions"); - - double total_prediction_ms = 0.0; - - for (G1HeapRegion* r : *optional_regions) { - double prediction_ms = predict_region_total_time_ms(r, false); - - if (prediction_ms > time_remaining_ms) { - log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", - prediction_ms, r->hrm_index(), time_remaining_ms); - break; - } - // This region will be included in the next optional evacuation. - - total_prediction_ms += prediction_ms; - time_remaining_ms -= prediction_ms; - - selected_regions->append(r); - } - - log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms", - selected_regions->length(), optional_regions->length(), total_prediction_ms); -} - void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) { start_adding_survivor_regions(); diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 98d44408467..9a6ffb570be 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -335,27 +335,7 @@ class G1Policy: public CHeapObj { // Amount of allowed waste in bytes in the collection set. size_t allowed_waste_in_collection_set() const; - // Calculate and fill in the initial, optional and pinned old gen candidate regions from - // the given candidate list and the remaining time. - // Returns the remaining time. - double select_candidates_from_marking(G1CollectionCandidateList* marking_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions); - - void select_candidates_from_retained(G1CollectionCandidateList* retained_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions); - - // Calculate the number of optional regions from the given collection set candidates, - // the remaining time and the maximum number of these regions and return the number - // of actually selected regions in num_optional_regions. - void calculate_optional_collection_set_regions(G1CollectionCandidateRegionList* optional_old_regions, - double time_remaining_ms, - G1CollectionCandidateRegionList* selected); + private: @@ -423,12 +403,12 @@ class G1Policy: public CHeapObj { size_t desired_survivor_size(uint max_regions) const; +public: // Fraction used when predicting how many optional regions to include in // the CSet. This fraction of the available time is used for optional regions, // the rest is used to add old regions to the normal CSet. double optional_prediction_fraction() const { return 0.2; } -public: // Fraction used when evacuating the optional regions. This fraction of the // remaining time is used to choose what regions to include in the evacuation. double optional_evacuation_fraction() const { return 0.75; } From 3359518986bd12b0d97e5df5b0154d0539639818 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 7 Oct 2024 16:28:02 +0000 Subject: [PATCH 07/16] 8341593: Problemlist java/foreign/TestUpcallStress.java in Xcomp mode Reviewed-by: jvernee --- test/jdk/ProblemList-Xcomp.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 2fc09ee4df4..988b95a1b35 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -29,4 +29,5 @@ java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 8318668 generic-all +java/foreign/TestUpcallStress.java 8341584 generic-all com/sun/jdi/InterruptHangTest.java 8043571 generic-all From d0c5e4bc50cc2cbb65efe827ae8cf3e077f45e07 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Mon, 7 Oct 2024 16:32:01 +0000 Subject: [PATCH 08/16] 8341373: Open source closed frame tests # 4 Reviewed-by: prr --- .../awt/Frame/AddRemoveMenuBarTest_5.java | 120 ++++++++++++++++++ .../java/awt/Frame/FrameResizableTest.java | 97 ++++++++++++++ test/jdk/java/awt/Frame/I18NTitle.java | 65 ++++++++++ .../jdk/java/awt/Frame/MenuBarOffsetTest.java | 81 ++++++++++++ test/jdk/java/awt/Frame/MinimumSizeTest.java | 114 +++++++++++++++++ 5 files changed, 477 insertions(+) create mode 100644 test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java create mode 100644 test/jdk/java/awt/Frame/FrameResizableTest.java create mode 100644 test/jdk/java/awt/Frame/I18NTitle.java create mode 100644 test/jdk/java/awt/Frame/MenuBarOffsetTest.java create mode 100644 test/jdk/java/awt/Frame/MinimumSizeTest.java diff --git a/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java new file mode 100644 index 00000000000..f5f1018c262 --- /dev/null +++ b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Robot; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @key headful + * @bug 4159883 + * @summary Adding/Removing a menu causes frame to unexpected small size + * @requires (os.family == "linux" | os.family == "windows") + */ + +public class AddRemoveMenuBarTest_5 { + + static Frame frame; + static MenuBar menu; + static Button btnAdd, btnRemove; + static Dimension oldSize; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + oldSize = frame.getSize(); + changeMenubar(true); + }); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + checkSize(); + changeMenubar(false); + }); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::checkSize); + } finally { + EventQueue.invokeAndWait(frame::dispose); + } + } + + public static void initAndShowGui() { + frame = new Frame(); + frame.setLocationRelativeTo(null); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + System.out.println("Frame size:" + frame.getSize().toString()); + System.out.println("Button size:" + btnAdd.getSize().toString()); + } + }); + frame.add("West", btnAdd = new Button("TRY:ADD")); + frame.add("East", btnRemove = new Button("TRY:REMOVE")); + + + btnAdd.addActionListener((e) -> changeMenubar(true)); + btnRemove.addActionListener((e) -> changeMenubar(false)); + frame.setSize(500, 100); + frame.setVisible(true); + } + + private static void changeMenubar(boolean enable) { + if (enable) { + menu = new MenuBar(); + menu.add(new Menu("BAAAAAAAAAAAAAAA")); + menu.add(new Menu("BZZZZZZZZZZZZZZZ")); + menu.add(new Menu("BXXXXXXXXXXXXXXX")); + } else { + menu = null; + } + frame.setMenuBar(menu); + frame.invalidate(); + frame.validate(); + + System.out.println("Frame size:" + frame.getSize().toString()); + System.out.println("Button size:" + btnAdd.getSize().toString()); + } + + private static void checkSize() { + Dimension newSize = frame.getSize(); + if (!oldSize.equals(newSize)) { + throw new RuntimeException("Frame size changed: old %s new %s" + .formatted(oldSize, newSize)); + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizableTest.java b/test/jdk/java/awt/Frame/FrameResizableTest.java new file mode 100644 index 00000000000..4734ce71670 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizableTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 1231233 + * @summary Tests whether the resizable property of a Frame is + * respected after it is set. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizableTest + */ + +public class FrameResizableTest { + private static final String INSTRUCTIONS = """ + There is a frame with two buttons and a label. The label + reads 'true' or 'false' to indicate whether the frame can be + resized or not. + + When the first button, 'Set Resizable', is + clicked, you should be able to resize the frame. + When the second button, 'UnSet Resizable', is clicked, you should + not be able to resize the frame. + + A frame is resized in a way which depends upon the window manager (WM) running. + You may resize the frame by dragging the corner resize handles or the borders, + or you may use the title bar's resize menu items and buttons. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizableTest Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(FrameResizable::new) + .build() + .awaitAndCheck(); + } + + private static class FrameResizable extends Frame { + Label label; + Button buttonResizable; + Button buttonNotResizable; + + public FrameResizable() { + super("FrameResizable"); + setResizable(false); + Panel panel = new Panel(); + + add("North", panel); + ActionListener actionListener = (e) -> { + if (e.getSource() == buttonResizable) { + setResizable(true); + } else if (e.getSource() == buttonNotResizable) { + setResizable(false); + } + label.setText("Resizable: " + isResizable()); + }; + + panel.add(buttonResizable = new Button("Set Resizable")); + panel.add(buttonNotResizable = new Button("UnSet Resizable")); + panel.add(label = new Label("Resizable: " + isResizable())); + buttonResizable.addActionListener(actionListener); + buttonNotResizable.addActionListener(actionListener); + + setSize(400, 200); + } + } +} diff --git a/test/jdk/java/awt/Frame/I18NTitle.java b/test/jdk/java/awt/Frame/I18NTitle.java new file mode 100644 index 00000000000..7127fc3dfbf --- /dev/null +++ b/test/jdk/java/awt/Frame/I18NTitle.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Window; + +/* + * @test + * @bug 6269884 4929291 + * @summary Tests that title which contains mix of non-English characters is displayed correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual I18NTitle + */ + +public class I18NTitle { + private static final String INSTRUCTIONS = """ + You will see a frame with some title (S. Chinese, Cyrillic and German). + Please check if non-English characters are visible and compare + the visible title with the same string shown in the label + (it should not look worse than the label). + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("I18NTitle Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(I18NTitle::createAndShowGUI) + .build() + .awaitAndCheck(); + } + + private static Window createAndShowGUI() { + String s = "\u4e2d\u6587\u6d4b\u8bd5 \u0420\u0443\u0441\u0441\u043a\u0438\u0439 Zur\u00FCck"; + Frame frame = new Frame(s); + frame.setLayout(new BorderLayout()); + Label l = new Label(s); + frame.add(l); + frame.setSize(400, 100); + return frame; + } +} diff --git a/test/jdk/java/awt/Frame/MenuBarOffsetTest.java b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java new file mode 100644 index 00000000000..65a4a8ef4bd --- /dev/null +++ b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Menu; +import java.awt.MenuBar; + +/* + * @test + * @bug 4180577 + * @summary offset problems with menus in frames: (2 * 1) should be (2 * menuBarBorderSize) + * @requires (os.family == "linux" | os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarOffsetTest +*/ + +public class MenuBarOffsetTest { + private static final String INSTRUCTIONS = """ + If a menubar containing a menubar item labeled Test appears. + in a frame, and fits within the frame, press Pass, else press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MenuBarOffsetTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameTest::new) + .build() + .awaitAndCheck(); + } + + private static class FrameTest extends Frame { + public FrameTest() { + super("MenuBarOffsetTest FrameTest"); + MenuBar m = new MenuBar(); + setMenuBar(m); + Menu test = m.add(new Menu("Test")); + test.add("1"); + test.add("2"); + setSize(100, 100); + } + + public void paint(Graphics g) { + setForeground(Color.red); + Insets i = getInsets(); + Dimension d = getSize(); + System.err.println(getBounds()); + System.err.println("" + i); + + g.drawRect(i.left, i.top, + d.width - i.left - i.right - 1, + d.height - i.top - i.bottom - 1); + } + } +} diff --git a/test/jdk/java/awt/Frame/MinimumSizeTest.java b/test/jdk/java/awt/Frame/MinimumSizeTest.java new file mode 100644 index 00000000000..cfff77be5f9 --- /dev/null +++ b/test/jdk/java/awt/Frame/MinimumSizeTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.imageio.ImageIO; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +/* + * @test + * @key headful + * @bug 1256759 + * @summary Checks that Frames with a very small size don't cause Motif + * to generate VendorShells which consume the entire desktop. + */ + +public class MinimumSizeTest { + + private static final Color BG_COLOR = Color.RED; + private static Frame backgroundFrame; + private static Frame testedFrame; + + private static Robot robot; + private static final Point location = new Point(200, 200); + private static final Point[] testPointLocations = { + new Point(100, 200), + new Point(200, 100), + new Point(450, 210), + new Point(210, 350), + }; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + try { + EventQueue.invokeAndWait(MinimumSizeTest::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + test(); + System.out.println("Test passed."); + } finally { + EventQueue.invokeAndWait(() -> { + backgroundFrame.dispose(); + testedFrame.dispose(); + }); + } + } + + private static void test() { + for (Point testLocation : testPointLocations) { + Color pixelColor = robot.getPixelColor(testLocation.x, testLocation.y); + + if (!pixelColor.equals(BG_COLOR)) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + BufferedImage screenCapture = robot.createScreenCapture(new Rectangle(screenSize)); + try { + ImageIO.write(screenCapture, "png", new File("failure.png")); + } catch (IOException ignored) {} + throw new RuntimeException("Pixel color does not match expected color %s at %s" + .formatted(pixelColor, testLocation)); + } + } + } + + private static void initAndShowGui() { + backgroundFrame = new Frame("MinimumSizeTest background"); + backgroundFrame.setUndecorated(true); + backgroundFrame.setBackground(BG_COLOR); + backgroundFrame.setBounds(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())); + backgroundFrame.setVisible(true); + + testedFrame = new MinimumSizeTestFrame(); + testedFrame.setVisible(true); + } + + private static class MinimumSizeTestFrame extends Frame { + public MinimumSizeTestFrame() { + super("MinimumSizeTest"); + setVisible(true); + setBackground(Color.BLUE); + setSize(0, 0); + setLocation(location); + } + } +} + From f7bb647dc88f835fe819e7ab0434c931f243304a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Mon, 7 Oct 2024 16:34:08 +0000 Subject: [PATCH 09/16] 8341595: Clean up iteration of CEN headers in ZipFile.Source.initCEN Reviewed-by: lancea, redestad --- .../share/classes/java/util/zip/ZipFile.java | 28 +- .../java/util/zip/ZipFile/CenSizeMaximum.java | 246 ++++++++++++++++++ 2 files changed, 261 insertions(+), 13 deletions(-) create mode 100644 test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 43b2261f1c6..a6b6dce1a14 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1239,12 +1239,12 @@ private int checkAndAddEntry(int pos, int index) int nlen = CENNAM(cen, pos); int elen = CENEXT(cen, pos); int clen = CENCOM(cen, pos); - long headerSize = (long)CENHDR + nlen + clen + elen; + int headerSize = CENHDR + nlen + clen + elen; // CEN header size + name length + comment length + extra length // should not exceed 65,535 bytes per the PKWare APP.NOTE // 4.4.10, 4.4.11, & 4.4.12. Also check that current CEN header will // not exceed the length of the CEN array - if (headerSize > 0xFFFF || pos + headerSize > cen.length) { + if (headerSize > 0xFFFF || pos > cen.length - headerSize) { zerror("invalid CEN header (bad header size)"); } @@ -1768,18 +1768,18 @@ private void initCEN(int knownTotal) throws IOException { // Iterate through the entries in the central directory int idx = 0; // Index into the entries array int pos = 0; - int entryPos = CENHDR; - int limit = cen.length; manifestNum = 0; - while (entryPos <= limit) { + int limit = cen.length - CENHDR; + while (pos <= limit) { if (idx >= entriesLength) { // This will only happen if the ZIP file has an incorrect // ENDTOT field, which usually means it contains more than // 65535 entries. - initCEN(countCENHeaders(cen, limit)); + initCEN(countCENHeaders(cen)); return; } + int entryPos = pos + CENHDR; // Checks the entry and adds values to entries[idx ... idx+2] int nlen = checkAndAddEntry(pos, idx); idx += 3; @@ -1810,7 +1810,6 @@ private void initCEN(int knownTotal) throws IOException { } // skip to the start of the next entry pos = nextEntryPos(pos, entryPos, nlen); - entryPos = pos + CENHDR; } // Adjust the total entries @@ -2034,17 +2033,20 @@ private int getMetaVersion(int off, int len) { /** * Returns the number of CEN headers in a central directory. - * Will not throw, even if the ZIP file is corrupt. * * @param cen copy of the bytes in a ZIP file's central directory - * @param size number of bytes in central directory + * @throws ZipException if a CEN header exceeds the length of the CEN array */ - private static int countCENHeaders(byte[] cen, int size) { + private static int countCENHeaders(byte[] cen) throws ZipException { int count = 0; - for (int p = 0; - p + CENHDR <= size; - p += CENHDR + CENNAM(cen, p) + CENEXT(cen, p) + CENCOM(cen, p)) + for (int p = 0; p <= cen.length - CENHDR;) { + int headerSize = CENHDR + CENNAM(cen, p) + CENEXT(cen, p) + CENCOM(cen, p); + if (p > cen.length - headerSize) { + zerror("invalid CEN header (bad header size)"); + } + p += headerSize; count++; + } return count; } } diff --git a/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java b/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java new file mode 100644 index 00000000000..a63464eb72b --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8341595 + * @modules java.base/jdk.internal.util + * @summary Verify that ZipFile can read from a ZIP file with a maximally large CEN size + * @run junit/othervm/manual -Xmx2500M CenSizeMaximum + */ + +import jdk.internal.util.ArraysSupport; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.*; + +public class CenSizeMaximum { + + // Maximum allowed CEN size allowed by the ZipFile implementation + static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + + /** + * From the APPNOTE.txt specification: + * 4.4.10 file name length: (2 bytes) + * 4.4.11 extra field length: (2 bytes) + * 4.4.12 file comment length: (2 bytes) + * + * The length of the file name, extra field, and comment + * fields respectively. The combined length of any + * directory record and these three fields SHOULD NOT + * generally exceed 65,535 bytes. + *. + * Create a maximum extra field which does not exceed 65,535 bytes + */ + static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR; + + // Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings' + static final short UNKNOWN_ZIP_TAG = (short) 0x9902; + + // The size of one CEN header, including the name and the extra field + static final int CEN_HEADER_SIZE = ZipFile.CENHDR + MAX_EXTRA_FIELD_SIZE; + + // The size of the extra data field header (tag id + data block length) + static final int EXTRA_FIELD_HEADER_SIZE = 2 * Short.BYTES; + + // Zip file to create for testing + private Path hugeZipFile = Path.of("cen-size-on-limit.zip"); + + /** + * Clean up ZIP file created in this test + */ + @AfterEach + public void cleanup() throws IOException { + //Files.deleteIfExists(hugeZipFile); + } + + /** + * Validates that ZipFile opens a ZIP file with a CEN size close + * to the {@link #MAX_CEN_SIZE} implementation limit. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + public void maximumCenSize() throws IOException { + int numCenHeaders = zipWithWithExactCenSize(MAX_CEN_SIZE, true, false); + try (var zf = new ZipFile(hugeZipFile.toFile())) { + assertEquals(numCenHeaders, zf.size()); + } + } + + /** + * Validates that ZipFile rejects a ZIP where the last CEN record + * overflows the CEN size and the END header CENTOT field is smaller + * than the actual number of headers + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + public void lastCENHeaderBadSize() throws IOException { + int numCenHeaders = zipWithWithExactCenSize(1024, true, true); + ZipException zipException = assertThrows(ZipException.class, () -> { + try (var zf = new ZipFile(hugeZipFile.toFile())) { + assertEquals(numCenHeaders, zf.size()); + } + }); + assertEquals("invalid CEN header (bad header size)", zipException.getMessage()); + + } + + /** + * Produce a ZIP file with an exact CEN size. To minimize the number of CEN headers + * written, maximally large, empty extra data blocks are written sparsely. + * + * @param cenSize the exact CEN size of the ZIP file to produce + * @param invalidateEndTotal whether to decrement the END header's TOT field by one + * @return the number of CEN headers produced + * @throws IOException if an unexpected IO error occurs + */ + private int zipWithWithExactCenSize(long cenSize, boolean invalidateEndTotal, boolean overflowLastCEN) + throws IOException { + // Sanity check + assertTrue(cenSize <= MAX_CEN_SIZE); + + // The number of CEN headers we need to write + int numCenHeaders = (int) (cenSize / CEN_HEADER_SIZE) + 1; + // Size if all extra data fields were of maximum size + long overSized = numCenHeaders * (long) CEN_HEADER_SIZE; + // Length to trim from the first CEN's extra data + int negativPadding = (int) (overSized - cenSize); + int firstExtraSize = MAX_EXTRA_FIELD_SIZE - negativPadding; + + // Sanity check + long computedCenSize = (numCenHeaders -1L ) * CEN_HEADER_SIZE + ZipEntry.CENHDR + firstExtraSize; + assertEquals(computedCenSize, cenSize); + + // A CEN header, followed by the four-bytes extra data header + ByteBuffer cenHeader = createCENHeader(); + // An END header + ByteBuffer endHeader = createENDHeader(); + // Update the END header + if (invalidateEndTotal) { + // To trigger countCENHeaders + endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders -1 & 0xFFFF)); + } else { + endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders & 0xFFFF)); + } + // Update CEN size and offset fields + endHeader.putInt(ZipEntry.ENDSIZ, (int) (cenSize & 0xFFFFFFFFL)); + endHeader.putInt(ZipEntry.ENDOFF, 0); + + // When creating a sparse file, the file must not already exit + Files.deleteIfExists(hugeZipFile); + + // Open a FileChannel for writing a sparse file + EnumSet options = EnumSet.of(StandardOpenOption.CREATE_NEW, + StandardOpenOption.WRITE, + StandardOpenOption.SPARSE); + + try (FileChannel channel = FileChannel.open(hugeZipFile, options)) { + // Write CEN headers + for (int i = 0; i < numCenHeaders; i++) { + // The first CEN header has trimmed extra data + int extraSize = i == 0 ? firstExtraSize : MAX_EXTRA_FIELD_SIZE; + if (overflowLastCEN && i == numCenHeaders - 1) { + // make last CEN header overflow the CEN size + cenHeader.putShort(ZipEntry.CENNAM, Short.MAX_VALUE); + } + // update elen field + cenHeader.putShort(ZipEntry.CENEXT, (short) (extraSize & 0xFFFF)); + // update data block len of the extra field header + short dlen = (short) ((extraSize - EXTRA_FIELD_HEADER_SIZE) & 0xFFFF); + cenHeader.putShort(ZipEntry.CENHDR + Short.BYTES, dlen); + // Write the CEN header plus the four-byte extra header + channel.write(cenHeader.rewind()); + // Sparse "write" of the extra data block + channel.position(channel.position() + extraSize - EXTRA_FIELD_HEADER_SIZE); + } + // Sanity check + assertEquals(cenSize, channel.position()); + // Write the END header + channel.write(endHeader.rewind()); + } + return numCenHeaders; + } + + // Creates a ByteBuffer representing a CEN header with a trailing extra field header + private ByteBuffer createCENHeader() throws IOException { + byte[] bytes = smallZipfile(); + ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + int endOff = bytes.length - ZipEntry.ENDHDR; + int cenSize = buf.getInt(endOff + ZipEntry.ENDSIZ); + int cenOff = buf.getInt(endOff + ZipEntry.ENDOFF); + return ByteBuffer.wrap( + Arrays.copyOfRange(bytes, cenOff, cenOff + ZipEntry.CENHDR + EXTRA_FIELD_HEADER_SIZE) + ).order(ByteOrder.LITTLE_ENDIAN); + } + + // Creates a ByteBuffer representing an END header + private ByteBuffer createENDHeader() throws IOException { + byte[] bytes = smallZipfile(); + ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + int endOff = bytes.length - ZipEntry.ENDHDR; + return ByteBuffer.wrap( + Arrays.copyOfRange(bytes, endOff, endOff + ZipEntry.ENDHDR) + ).order(ByteOrder.LITTLE_ENDIAN); + } + + // Create a byte array with a minimal ZIP file + private static byte[] smallZipfile() throws IOException { + var out = new ByteArrayOutputStream(); + try (var zo = new ZipOutputStream(out)) { + ZipEntry entry = new ZipEntry(""); + entry.setExtra(makeDummyExtraField()); + zo.putNextEntry(entry); + } + return out.toByteArray(); + } + + // Create a minimally sized extra field + private static byte[] makeDummyExtraField() { + byte[] extra = new byte[EXTRA_FIELD_HEADER_SIZE]; + // Little-endian ByteBuffer for updating the header fields + ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN); + + // We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings' + buffer.putShort(UNKNOWN_ZIP_TAG); + + // Size of the actual (empty) data + buffer.putShort((short) 0); + return extra; + } +} From fc7244da96a9423146c4a46bcc3bbfc205900c3b Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Mon, 7 Oct 2024 17:42:17 +0000 Subject: [PATCH 10/16] 8340713: Open source DnD tests - Set5 Reviewed-by: azvegint, dnguyen --- test/jdk/ProblemList.txt | 3 + .../java/awt/dnd/DragExitBeforeDropTest.java | 257 ++++++++++++++++++ test/jdk/java/awt/dnd/DragThresholdTest.java | 134 +++++++++ .../java/awt/dnd/WinMoveFileToShellTest.java | 131 +++++++++ 4 files changed, 525 insertions(+) create mode 100644 test/jdk/java/awt/dnd/DragExitBeforeDropTest.java create mode 100644 test/jdk/java/awt/dnd/DragThresholdTest.java create mode 100644 test/jdk/java/awt/dnd/WinMoveFileToShellTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 12954e6174d..1f96e2b0f42 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -128,6 +128,8 @@ java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java 8060176 java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java 8060176 windows-all,macosx-all java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java 8171510 macosx-all java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8288839 windows-x64 +java/awt/dnd/DragExitBeforeDropTest.java 8242805 macosx-all +java/awt/dnd/DragThresholdTest.java 8076299 macosx-all java/awt/Focus/ChoiceFocus/ChoiceFocus.java 8169103 windows-all,macosx-all java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java 8198618 macosx-all java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all @@ -806,3 +808,4 @@ java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all +java/awt/dnd/WinMoveFileToShellTest.java 8341665 windows-all diff --git a/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java new file mode 100644 index 00000000000..2ef778a18ba --- /dev/null +++ b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/* + * @test + * @bug 4395290 + * @key headful + * @summary tests that dragExit() is not called before drop() + */ + +public class DragExitBeforeDropTest { + private static Frame frame; + private static final DragSourceButton dragSourceButton = new DragSourceButton(); + private static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + private static volatile Point srcPoint; + private static volatile Point dstPoint; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(DragExitBeforeDropTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = dragSourceButton.getLocationOnScreen(); + Dimension d = dragSourceButton.getSize(); + p.translate(d.width / 2, d.height / 2); + srcPoint = p; + + p = dropTargetPanel.getLocationOnScreen(); + d = dropTargetPanel.getSize(); + p.translate(d.width / 2, d.height / 2); + dstPoint = p; + }); + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!dropTargetPanel.getStatus()) { + throw new RuntimeException("The test failed: dragExit()" + + " is called before drop()"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("DragExitBeforeDropTest"); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourceButton); + frame.add(dropTargetPanel); + frame.setLocationRelativeTo(null); + frame.setSize(300, 400); + frame.setVisible(true); + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } + + private static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) {} + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) {} + + public void dropActionChanged(DragSourceDragEvent dsde) {} + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = + new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + } + + private static class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + volatile boolean testPassed = true; + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public boolean getStatus() { + return testPassed; + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) { + testPassed = false; + } + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if(dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + add(comp); + } + } +} + + + diff --git a/test/jdk/java/awt/dnd/DragThresholdTest.java b/test/jdk/java/awt/dnd/DragThresholdTest.java new file mode 100644 index 00000000000..bcb3bbf91c2 --- /dev/null +++ b/test/jdk/java/awt/dnd/DragThresholdTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; + +/* + @test + @key headful + @bug 4415175 + @summary tests DragSource.getDragThreshold() and + that the AWT default drag gesture recognizers + honor the drag gesture motion threshold +*/ + +public class DragThresholdTest { + private static Frame frame; + private static Panel panel; + private static MouseEvent lastMouseEvent; + private static volatile boolean failed; + private static volatile Point startPoint; + private static volatile Point endPoint; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(DragThresholdTest::createAndShowDnD); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = panel.getLocationOnScreen(); + p.translate(50, 50); + startPoint = p; + endPoint = new Point(p.x + 2 * DragSource.getDragThreshold(), + p.y + 2 * DragSource.getDragThreshold()); + }); + + robot.mouseMove(startPoint.x, startPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (Point p = new Point(startPoint); !p.equals(endPoint); + p.translate(sign(endPoint.x - p.x), + sign(endPoint.y - p.y))) { + robot.mouseMove(p.x, p.y); + robot.delay(100); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(200); + + if (failed) { + throw new RuntimeException("drag gesture recognized too early"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowDnD() { + frame = new Frame("DragThresholdTest"); + panel = new Panel(); + // Mouse motion listener mml is added to the panel first. + // We rely on it that this listener will be called first. + panel.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseDragged(MouseEvent evt) { + lastMouseEvent = evt; + System.out.println(evt); + } + }); + frame.add(panel); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + + DragGestureListener dgl = dge -> { + Point dragOrigin = dge.getDragOrigin(); + int diffx = Math.abs(dragOrigin.x - lastMouseEvent.getX()); + int diffy = Math.abs(dragOrigin.y - lastMouseEvent.getY()); + System.out.println("dragGestureRecognized(): " + + " diffx=" + diffx + " diffy=" + diffy + + " DragSource.getDragThreshold()=" + + DragSource.getDragThreshold()); + if (diffx <= DragSource.getDragThreshold() && + diffy <= DragSource.getDragThreshold()) { + failed = true; + System.out.println("drag gesture recognized too early!"); + } + }; + + // Default drag gesture recognizer is a mouse motion listener. + // It is added to the panel second. + new DragSource().createDefaultDragGestureRecognizer( + panel, + DnDConstants.ACTION_COPY_OR_MOVE, dgl); + frame.setVisible(true); + } + + private static int sign(int n) { + return Integer.compare(n, 0); + } +} diff --git a/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java new file mode 100644 index 00000000000..5ae7dd3890d --- /dev/null +++ b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceListener; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @bug 4414739 + * @requires (os.family == "windows") + * @summary verifies that getDropSuccess() returns correct value for moving + a file from a Java drag source to the Windows shell + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WinMoveFileToShellTest + */ + +public class WinMoveFileToShellTest { + private static final String INSTRUCTIONS = """ + Drag from the frame titled "Drag Frame" and drop on to Windows Desktop. + After Drag and Drop, check for "Drop Success" status in the log area. + If "Drop Success" is true press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(WinMoveFileToShellTest::createAndShowUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("Drag Frame"); + final DragSourceListener dsl = new DragSourceAdapter() { + public void dragDropEnd(DragSourceDropEvent e) { + PassFailJFrame.log("Drop Success: " + e.getDropSuccess()); + } + }; + + DragGestureListener dgl = dge -> { + File file = new File(System.getProperty("test.classes", ".") + + File.separator + "move.me"); + try { + file.createNewFile(); + } catch (IOException exc) { + exc.printStackTrace(); + } + ArrayList list = new ArrayList<>(); + list.add(file); + dge.startDrag(null, new FileListSelection(list), dsl); + }; + + new DragSource().createDefaultDragGestureRecognizer(frame, + DnDConstants.ACTION_MOVE, dgl); + frame.setSize(200, 100); + return frame; + } + + private static class FileListSelection implements Transferable { + private static final int FL = 0; + + private static final DataFlavor[] flavors = + new DataFlavor[] { DataFlavor.javaFileListFlavor }; + + + private List data; + + public FileListSelection(List data) { + this.data = data; + } + + public DataFlavor[] getTransferDataFlavors() { + return flavors.clone(); + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + for (DataFlavor dataFlavor : flavors) { + if (flavor.equals(dataFlavor)) { + return true; + } + } + return false; + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + if (flavor.equals(flavors[FL])) { + return data; + } else { + throw new UnsupportedFlavorException(flavor); + } + } + } +} From 23f3ca254a2558ddaaf29714b0a5fc22daeed013 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Mon, 7 Oct 2024 19:33:48 +0000 Subject: [PATCH 11/16] 8330206: Bump minimum boot jdk to JDK 23 Reviewed-by: darcy, iris, erikj --- make/conf/github-actions.conf | 20 ++++++++++---------- make/conf/jib-profiles.js | 4 ++-- make/conf/version-numbers.conf | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index eca6c05033d..a6b383daa8f 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -29,21 +29,21 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=7.4+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=41536f115668308ecf4eba92aaf6acaeb0936225828b741efd83b6173ba82963 +LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=08fea92724127c6fa0f2e5ea0b07ff4951ccb1e2f22db3c21eebbd7347152a67 ALPINE_LINUX_X64_BOOT_JDK_EXT=tar.gz -ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin22-binaries/releases/download/jdk-22.0.2%2B9/OpenJDK22U-jdk_x64_alpine-linux_hotspot_22.0.2_9.tar.gz -ALPINE_LINUX_X64_BOOT_JDK_SHA256=49f73414824b1a7c268a611225fa4d7ce5e25600201e0f1cd59f94d1040b5264 +ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin23-binaries/releases/download/jdk-23%2B37/OpenJDK23U-jdk_x64_alpine-linux_hotspot_23_37.tar.gz +ALPINE_LINUX_X64_BOOT_JDK_SHA256=bff4c78f30d8d173e622bf2f40c36113df47337fc6d1ee5105ed2459841165aa MACOS_AARCH64_BOOT_JDK_EXT=tar.gz -MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-aarch64_bin.tar.gz -MACOS_AARCH64_BOOT_JDK_SHA256=3dab98730234e1a87aec14bcb8171d2cae101e96ff4eed1dab96abbb08e843fd +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=9527bf080a74ae6dca51df413aa826f0c011c6048885e4c8ad112172be8815f3 MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=e8b3ec7a7077711223d31156e771f11723cd7af31c2017f1bd2eda20855940fb +MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=5c3a909fd2079d0e376dd43c85c4f7d02d08914866f196480bd47784b2a0121e WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=f2a9b9ab944e71a64637fcdc6b13a1188cf02d4eb9ecf71dc927e98b3e45f5dc +WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=cba5013874ba50cae543c86fe6423453816c77281e2751a8a9a633d966f1dc04 diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 30c45d4cde1..a85c20b2098 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -390,8 +390,8 @@ var getJibProfilesCommon = function (input, data) { }; }; - common.boot_jdk_version = "22"; - common.boot_jdk_build_number = "36"; + common.boot_jdk_version = "23"; + common.boot_jdk_build_number = "37"; common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-" + common.boot_jdk_version + (input.build_os == "macosx" ? ".jdk/Contents/Home" : ""); diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 1d47c2cddd0..055f9ca8866 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -37,6 +37,6 @@ DEFAULT_VERSION_DATE=2025-03-18 DEFAULT_VERSION_CLASSFILE_MAJOR=68 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="22 23 24" +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="23 24" DEFAULT_JDK_SOURCE_TARGET_VERSION=24 DEFAULT_PROMOTED_VERSION_PRE=ea From 4d50cbb5a73ad1f84ecd6a895045ecfdb0835adc Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Mon, 7 Oct 2024 21:29:21 +0000 Subject: [PATCH 12/16] 8341278: Open source few TrayIcon tests - Set7 Reviewed-by: azvegint --- test/jdk/ProblemList.txt | 2 + .../java/awt/TrayIcon/ClearPrevImageTest.java | 126 ++++++++++++++++ .../awt/TrayIcon/FocusLostAfterTrayTest.java | 136 ++++++++++++++++++ test/jdk/java/awt/TrayIcon/MouseMoveTest.java | 107 ++++++++++++++ .../awt/TrayIcon/TrayIconKeySelectTest.java | 122 ++++++++++++++++ 5 files changed, 493 insertions(+) create mode 100644 test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java create mode 100644 test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java create mode 100644 test/jdk/java/awt/TrayIcon/MouseMoveTest.java create mode 100644 test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1f96e2b0f42..303e449e4a5 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -212,6 +212,8 @@ java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java 8150540,8295300 windows java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java 8150540 windows-all java/awt/TrayIcon/TrayIconPopup/TrayIconPopupClickTest.java 8150540 windows-all,macosx-all java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java 8150540 windows-all +java/awt/TrayIcon/MouseMoveTest.java 8203053 linux-all +java/awt/TrayIcon/TrayIconKeySelectTest.java 8341557 windows-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeAndClick.java 8197936 macosx-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeDynamicallyAndClick.java 8013450 macosx-all diff --git a/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java new file mode 100644 index 00000000000..e97f645bec5 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267936 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests that the previous image in TrayIcon is cleared + * when a new image is set + * @run main/manual ClearPrevImageTest + */ + +public class ClearPrevImageTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + This test checks that the previous image in TrayIcon is cleared + when a new image is set. + + When the test starts, a RED square TrayIcon is added + to the SystemTray (also, called Taskbar Status Area in MS Windows, + Notification Area in, GNOME and System Tray in KDE). + + You should see it change into YELLOW after 5 seconds. + If you still see RED TrayIcon after 5 seconds, + press FAIL, otherwise press PASS + """; + + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + PassFailJFrame passFailJFrame + = PassFailJFrame.builder() + .title("TrayIcon Change Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .build(); + + EventQueue.invokeAndWait(ClearPrevImageTest::createAndShowTrayIcon); + try { + changeTrayIcon(); + passFailJFrame.awaitAndCheck(); + } catch (Exception e) { + throw new RuntimeException("Test failed: ", e); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + Image img1 = createIcon(Color.RED); + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(img1); + icon.setImageAutoSize(true); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } + + private static void changeTrayIcon() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Image img2 = createIcon(Color.YELLOW); + icon.setImage(img2); + } + + private static Image createIcon(Color color) { + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(color); + g.fillRect(0, 0, 16, 16); + g.dispose(); + return image; + } +} diff --git a/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java new file mode 100644 index 00000000000..bd831ce94e4 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TextArea; +import java.awt.TrayIcon; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6269309 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests that focus is transferred properly back + * to toplevel after clicking on a tray icon. + * @run main/manual FocusLostAfterTrayTest + */ + +public class FocusLostAfterTrayTest { + private static SystemTray tray; + private static TrayIcon icon; + + private static final String INSTRUCTIONS = """ + This test checks that focus is transferred properly back + to top-level after clicking on a tray icon. + + When the test starts, a Frame with a text area & a RED tray icon + are shown. If you don't see a tray icon please make sure that + the tray area (also called Taskbar Status Area on MS Windows + Notification Area on Gnome or System Tray on KDE) is visible. + + Click with a mouse inside a text area and make sure that it has + received input focus. Then click on the tray icon and then back + on the text area and verify that it has input focus again. Repeat + the last step several times. Ensure that the text area always + has the input focus and there are no "FOCUS LOST" event + for text area in the log section. + + If above is true, Press PASS, else FAIL. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + try { + PassFailJFrame.builder() + .title("FocusLostAfterTrayTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(FocusLostAfterTrayTest::createAndShowTrayIcon) + .logArea() + .build() + .awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static Frame createAndShowTrayIcon() { + Frame frame = new Frame("FocusLostAfterTrayTest"); + frame.setBounds(100, 300, 200, 200); + frame.setLayout(new BorderLayout()); + TextArea ta = new TextArea(); + ta.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + PassFailJFrame.log("FOCUS GAINED: " + + e.getComponent().getClass().toString()); + } + @Override + public void focusLost(FocusEvent e) { + PassFailJFrame.log("FOCUS LOST !! " + + e.getComponent().getClass().toString()); + } + }); + frame.add(ta); + + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(Color.RED); + g.fillRect(0, 0, 16, 16); + g.dispose(); + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(image); + icon.setImageAutoSize(true); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + return frame; + } +} diff --git a/test/jdk/java/awt/TrayIcon/MouseMoveTest.java b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java new file mode 100644 index 00000000000..51d80ff127b --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267980 + * @summary PIT:Spurious MouseMoved events are triggered by Tray Icon + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual MouseMoveTest + */ + +public class MouseMoveTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + 1) You will see a tray icon (white square) in notification area, + 2) Move mouse pointer to the icon and leave it somewhere inside the icon, + 3) Verify that MOUSE_MOVE events are NOT triggered after you have STOPPED + moving mouse. + 4) If events are still triggered Press FAIL else PASS. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + PassFailJFrame passFailJFrame + = PassFailJFrame.builder() + .title("TrayIcon Change Test Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea() + .build(); + + try { + EventQueue.invokeAndWait(MouseMoveTest::createAndShowTrayIcon); + passFailJFrame.awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + BufferedImage img = new BufferedImage(32, 32, + BufferedImage.TYPE_INT_ARGB); + Graphics g = img.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, 32, 32); + g.dispose(); + + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(img); + icon.setImageAutoSize(true); + + icon.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent me){ + PassFailJFrame.log(me.toString()); + } + }); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } +} diff --git a/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java new file mode 100644 index 00000000000..5e41f546382 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267943 + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests the possibility of selecting a tray icon with the keyboard. + * @run main/manual TrayIconKeySelectTest + */ + +public class TrayIconKeySelectTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + Tests that TrayIcon is selectable with the keyboard + When the test is started you will see three-color icon + in the system tray. + + 1. Bring the focus to the icon with TAB. Press ENTER key. + - One or more ActionEvent should be generated + (see the output area of the test) + + 2. Bring the focus again to the icon. Press SPACE key twice. + - One or more ActionEvent should be generated. + + 3. Bring the focus again to the icon. Click on the icon with + the LEFT mouse button twice. + - One or more ActionEvent should be generated. + + 4. Again bring the focus to the icon. Click on the icon with + the LEFT mouse button just once. + - NO ActionEvent should be generated. + + 5. Repeat the 4th step with other mouse buttons. + + If all the above are true press PASS, else FAIL + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + PassFailJFrame passFailJFrame; + try { + passFailJFrame + = PassFailJFrame.builder() + .title("TrayIconKeySelectTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build(); + + EventQueue.invokeAndWait(TrayIconKeySelectTest::createAndShowTrayIcon); + passFailJFrame.awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + BufferedImage im = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics gr = im.createGraphics(); + gr.setColor(Color.white); + gr.fillRect(0, 0, 16, 5); + gr.setColor(Color.blue); + gr.fillRect(0, 5, 16, 10); + gr.setColor(Color.red); + gr.fillRect(0, 10, 16, 16); + gr.dispose(); + + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(im); + icon.setImageAutoSize(true); + icon.addActionListener(e -> PassFailJFrame.log(e.toString())); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } +} From d996ca863deef50ba7c1c8878cc4c202fa1a9d6b Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 7 Oct 2024 23:30:06 +0000 Subject: [PATCH 13/16] 8341581: Optimize BytecodeHelpers validate slot Reviewed-by: liach --- .../classfile/impl/BytecodeHelpers.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index 6994a62c0ab..4f4e1021712 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -88,9 +88,9 @@ public static Opcode aload(int slot) { case 2 -> Opcode.ALOAD_2; case 3 -> Opcode.ALOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ALOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ALOAD_W; throw slotOutOfBounds(slot); } @@ -104,9 +104,9 @@ public static Opcode fload(int slot) { case 2 -> Opcode.FLOAD_2; case 3 -> Opcode.FLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.FLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.FLOAD_W; throw slotOutOfBounds(slot); } @@ -120,9 +120,9 @@ public static Opcode dload(int slot) { case 2 -> Opcode.DLOAD_2; case 3 -> Opcode.DLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.DLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.DLOAD_W; throw slotOutOfBounds(slot); } @@ -136,9 +136,9 @@ public static Opcode lload(int slot) { case 2 -> Opcode.LLOAD_2; case 3 -> Opcode.LLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.LLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.LLOAD_W; throw slotOutOfBounds(slot); } @@ -152,9 +152,9 @@ public static Opcode iload(int slot) { case 2 -> Opcode.ILOAD_2; case 3 -> Opcode.ILOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ILOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ILOAD_W; throw slotOutOfBounds(slot); } @@ -180,9 +180,9 @@ public static Opcode astore(int slot) { case 2 -> Opcode.ASTORE_2; case 3 -> Opcode.ASTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ASTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ASTORE_W; throw slotOutOfBounds(slot); } @@ -196,9 +196,9 @@ public static Opcode fstore(int slot) { case 2 -> Opcode.FSTORE_2; case 3 -> Opcode.FSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.FSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.FSTORE_W; throw slotOutOfBounds(slot); } @@ -212,9 +212,9 @@ public static Opcode dstore(int slot) { case 2 -> Opcode.DSTORE_2; case 3 -> Opcode.DSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.DSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.DSTORE_W; throw slotOutOfBounds(slot); } @@ -228,9 +228,9 @@ public static Opcode lstore(int slot) { case 2 -> Opcode.LSTORE_2; case 3 -> Opcode.LSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.LSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.LSTORE_W; throw slotOutOfBounds(slot); } @@ -244,9 +244,9 @@ public static Opcode istore(int slot) { case 2 -> Opcode.ISTORE_2; case 3 -> Opcode.ISTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ISTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ISTORE_W; throw slotOutOfBounds(slot); } @@ -377,20 +377,20 @@ public static TypeKind convertToType(Opcode opcode) { public static void validateSlot(Opcode opcode, int slot, boolean load) { int size = opcode.sizeIfFixed(); if (size == 1 && slot == (load ? intrinsicLoadSlot(opcode) : intrinsicStoreSlot(opcode)) || - size == 2 && slot == (slot & 0xFF) || - size == 4 && slot == (slot & 0xFFFF)) + size == 2 && (slot & ~0xFF) == 0 || + size == 4 && (slot & ~0xFFFF) == 0) return; throw slotOutOfBounds(opcode, slot); } public static void validateSlot(int slot) { - if ((slot & 0xFFFF) != slot) + if ((slot & ~0xFFFF) != 0) throw slotOutOfBounds(slot); } public static boolean validateAndIsWideIinc(int slot, int val) { var ret = false; - if ((slot & 0xFF) != slot) { + if ((slot & ~0xFF) != 0) { validateSlot(slot); ret = true; } @@ -404,8 +404,8 @@ public static boolean validateAndIsWideIinc(int slot, int val) { } public static void validateRet(Opcode opcode, int slot) { - if (opcode == Opcode.RET && slot == (slot & 0xFF) || - opcode == Opcode.RET_W && slot == (slot & 0xFFFF)) + if (opcode == Opcode.RET && (slot & ~0xFF) == 0 || + opcode == Opcode.RET_W && (slot & ~0xFFFF) == 0) return; Objects.requireNonNull(opcode); throw slotOutOfBounds(opcode, slot); From 45a6359588996d25e5e8dadebdcd8d6a00ef786f Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 8 Oct 2024 01:26:16 +0000 Subject: [PATCH 14/16] 8341668: Shenandoah: assert(tail_bits < (idx_t)BitsPerWord) failed: precondition Reviewed-by: ysr --- src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp | 2 ++ .../share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp index 6b95303fb33..55d21b06e4b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp @@ -80,6 +80,8 @@ class ShenandoahSimpleBitMap { bool is_forward_consecutive_ones(idx_t start_idx, idx_t count) const; bool is_backward_consecutive_ones(idx_t last_idx, idx_t count) const; + static inline uintx tail_mask(uintx bit_number); + public: inline idx_t aligned_index(idx_t idx) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp index c047e1ed663..4582ab9a781 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp @@ -27,7 +27,7 @@ #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" -inline uintx tail_mask(uintx bit_number) { +inline uintx ShenandoahSimpleBitMap::tail_mask(uintx bit_number) { if (bit_number >= BitsPerWord) { return -1; } From b6a4047387dbe4e07df0032dfdd7ee5ad8f571a4 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 8 Oct 2024 06:33:11 +0000 Subject: [PATCH 15/16] 8339982: Open source several AWT Mouse tests - Batch 2 Reviewed-by: psadhukhan --- test/jdk/ProblemList.txt | 1 + .../DefaultScreenDeviceTest.java | 116 ++++++++++ test/jdk/java/awt/Mouse/DoubleClickTest.java | 88 +++++++ test/jdk/java/awt/Mouse/MouseClickCount.java | 69 ++++++ .../awt/Mouse/MouseDragEnterExitTest.java | 117 ++++++++++ test/jdk/java/awt/Mouse/MouseDragTest.java | 215 ++++++++++++++++++ 6 files changed, 606 insertions(+) create mode 100644 test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java create mode 100644 test/jdk/java/awt/Mouse/DoubleClickTest.java create mode 100644 test/jdk/java/awt/Mouse/MouseClickCount.java create mode 100644 test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java create mode 100644 test/jdk/java/awt/Mouse/MouseDragTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 303e449e4a5..664a7ac02da 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -437,6 +437,7 @@ java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.j java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersInKeyEvent.java 8157147 linux-all,windows-all,macosx-all +java/awt/Mouse/MouseClickCount.java 8017182 macosx-all java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java 6847163 linux-all java/awt/xembed/server/RunTestXEmbed.java 7034201 linux-all java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsDocModalTest.java 8164473 linux-all diff --git a/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java new file mode 100644 index 00000000000..b59460322da --- /dev/null +++ b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Label; +import java.awt.Rectangle; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; + +/* + * @test + * @bug 4473671 + * @summary Test to verify GraphicsEnvironment.getDefaultScreenDevice always + * returning first screen + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultScreenDeviceTest + */ + +public class DefaultScreenDeviceTest { + private static Frame testFrame; + + public static void main(String[] args) throws Exception { + GraphicsEnvironment ge = GraphicsEnvironment. + getLocalGraphicsEnvironment(); + GraphicsDevice[] gds = ge.getScreenDevices(); + if (gds.length < 2) { + System.out.println("Test requires at least 2 displays"); + return; + } + + String INSTRUCTIONS = """ + 1. The test is for systems which allows primary display + selection in multiscreen systems. + Set the system primary screen to be the rightmost + (i.e. the right screen in two screen configuration) + This can be done by going to OS Display Settings + selecting the screen and checking the 'Use this device + as primary monitor' checkbox. + 2. When done, click on 'Frame on Primary Screen' button and + see where the frame will pop up + 3. If Primary Frame pops up on the primary display, + the test passed, otherwise it failed + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static List initialize() { + Frame frame = new Frame("Default screen device test"); + GraphicsConfiguration gc = + GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + + testFrame = new Frame("Primary screen frame", gc); + frame.setLayout(new BorderLayout()); + frame.setSize(200, 200); + + Button b = new Button("Frame on Primary Screen"); + b.addActionListener(e -> { + if (testFrame != null) { + testFrame.setVisible(false); + testFrame.dispose(); + } + + testFrame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e1) { + testFrame.setVisible(false); + testFrame.dispose(); + } + }); + testFrame.add(new Label("This frame should be on the primary screen")); + testFrame.setBackground(Color.red); + testFrame.pack(); + Rectangle rect = gc.getBounds(); + testFrame.setLocation(rect.x + 100, rect.y + 100); + testFrame.setVisible(true); + }); + frame.add(b); + return List.of(testFrame, frame); + } +} diff --git a/test/jdk/java/awt/Mouse/DoubleClickTest.java b/test/jdk/java/awt/Mouse/DoubleClickTest.java new file mode 100644 index 00000000000..037332a4098 --- /dev/null +++ b/test/jdk/java/awt/Mouse/DoubleClickTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Event; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; + +/* + * @test + * @bug 4092370 + * @summary Test to verify double click + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DoubleClickTest + */ + +public class DoubleClickTest { + static TextArea ta = new TextArea("", 10, 40); + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Double click on the red area. + 2. Verify that the event reports click_count > 1 on + Double-Click. If click_count shows only 1 for every + Double-Clicks then test FAILS, else test PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Double-click Test"); + frame.setLayout(new BorderLayout()); + frame.add("East", new MyPanel(ta)); + frame.add("West", ta); + frame.setSize(200, 200); + return frame; + } +} + +class MyPanel extends Panel { + TextArea ta; + + MyPanel(TextArea ta) { + this.ta = ta; + setBackground(Color.red); + } + + public Dimension getPreferredSize() { + return new Dimension(50, 50); + } + + + public boolean mouseDown(Event event, int x, int y) { + ta.append("event click count= " + event.clickCount + "\n"); + return false; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseClickCount.java b/test/jdk/java/awt/Mouse/MouseClickCount.java new file mode 100644 index 00000000000..a63d24fcb9f --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseClickCount.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4199397 + * @summary Test to mouse click count + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseClickCount + */ + +public class MouseClickCount { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Clicking on Frame panel quickly will produce clickCount larger than 1 + in the TextArea the count is printed for each mouse click + 2. Verify that a left-button click followed by a right button click quickly + will not generate 1, 2, i.e. it's not considered a double clicking. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static Frame initialize() { + Frame f = new Frame("Mouse Click Count Test"); + final TextArea ta = new TextArea(); + f.add("South", ta); + f.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (e.getClickCount() == 1) ta.append("\n1"); + else ta.append(", " + e.getClickCount()); + } + }); + f.setSize(300, 500); + return f; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java new file mode 100644 index 00000000000..b2d8e446ffc --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +/* + * @test + * @bug 4141361 + * @summary Test to Ensures that mouse enter / exit is delivered to a new + * frame or component during a drag + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDragEnterExitTest + */ + +public class MouseDragEnterExitTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click on the blue frame, drag to the white frame, and back + You should get enter/exit messages for the frames when dragging + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MouseEvents.initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } +} + +class MouseEvents extends Frame { + static int WITH_WIDGET = 0; + + public MouseEvents(int mode) { + super("Mouse Drag Enter/Exit Test"); + setSize(300, 300); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log("Frame MOUSE_ENTERED" + ": " + " " + + e.getX() + " " + e.getY()); + } + + @Override + public void mouseExited(MouseEvent e) { + PassFailJFrame.log("Frame MOUSE_EXITED" + ": " + " " + + e.getX() + " " + e.getY()); + } + }); + + if (mode == WITH_WIDGET) { + setLayout(new BorderLayout()); + add("Center", new SimplePanel()); + } + } + + public static List initialize() { + MouseEvents m = new MouseEvents(MouseEvents.WITH_WIDGET); + m.setLocation(500, 300); + MouseEvents t = new MouseEvents(MouseEvents.WITH_WIDGET + 1); + t.setLocation(200, 200); + return List.of(m, t); + } +} + +class SimplePanel extends Panel { + public SimplePanel() { + super(); + setName("Test Panel"); + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log("Panel MOUSE_ENTERED" + ": " + " " + + e.getX() + " " + e.getY()); + } + + @Override + public void mouseExited(MouseEvent e) { + PassFailJFrame.log("Panel MOUSE_EXITED" + ": " + " " + + e.getX() + " " + e.getY()); + } + }); + setSize(100, 100); + setBackground(Color.blue); + } +} + diff --git a/test/jdk/java/awt/Mouse/MouseDragTest.java b/test/jdk/java/awt/Mouse/MouseDragTest.java new file mode 100644 index 00000000000..cb8be7b0de2 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseDragTest.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; + +/* + * @test + * @bug 4035189 + * @summary Test to verify that Drag events go to wrong component + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDragTest + */ + +class HeavySquare extends Canvas { + private final Color colorNormal; + private boolean gotADragEvent; + + public HeavySquare(Color color) { + colorNormal = color; + setBackground(colorNormal); + new MouseChecker(this); + addMouseMotionListener(new DragAdapter()); + addMouseListener(new PressReleaseAdapter()); + } + + class DragAdapter extends MouseMotionAdapter { + public void mouseDragged(MouseEvent ev) { + if (gotADragEvent) + return; + + Point mousePt = ev.getPoint(); + Dimension csize = getSize(); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= csize.width && + mousePt.y >= 0 && mousePt.y <= csize.height); + if (!inBounds) { + setBackground(Color.green); + } + gotADragEvent = true; + } + } + + class PressReleaseAdapter extends MouseAdapter { + public void mousePressed(MouseEvent ev) { + gotADragEvent = false; + } + + public void mouseReleased(MouseEvent ev) { + setBackground(colorNormal); + } + } + + public Dimension preferredSize() { + return new Dimension(50, 50); + } +} + +class MouseFrame extends Frame { + public MouseFrame() { + super("MouseDragTest"); + new MouseChecker(this); + setLayout(new FlowLayout()); + add(new HeavySquare(Color.red)); + add(new HeavySquare(Color.blue)); + setBounds(new Rectangle(20, 20, 400, 300)); + } +} + +public class MouseDragTest { + static Frame TestFrame; + + public MouseDragTest() { + TestFrame = new MouseFrame(); + } + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. A frame with two boxes will appear. Click and drag _very_ quickly + off one of the components. You will know you were quick enough + when the component you dragged off of turns green + 2. Repeat this several times on both boxes, ensuring you get them + to turn green. The components should revert to their original + color when you release the mouse + 3. The test FAILS if the component doesn't revert to original + color, else PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new MouseFrame()) + .build() + .awaitAndCheck(); + } +} + +class MouseChecker implements MouseListener, MouseMotionListener { + private boolean isPressed = false; + private MouseEvent evPrev = null; + private MouseEvent evPrevPrev = null; + + public MouseChecker(Component comp) { + comp.addMouseListener(this); + comp.addMouseMotionListener(this); + } + + private void recordEv(MouseEvent ev) { + evPrevPrev = evPrev; + evPrev = ev; + } + + private synchronized void failure(String str) { + PassFailJFrame.forceFail("Test Failed : "+str); + } + + public void mouseClicked(MouseEvent ev) { + if (!(evPrev.getID() == MouseEvent.MOUSE_RELEASED && + evPrevPrev.getID() == MouseEvent.MOUSE_PRESSED)) { + failure("Got mouse click without press/release preceding."); + } + recordEv(ev); + } + + public void mousePressed(MouseEvent ev) { + recordEv(ev); + if (isPressed) { + failure("Got two mouse presses without a release."); + } + isPressed = true; + } + + public void mouseReleased(MouseEvent ev) { + recordEv(ev); + if (!isPressed) { + failure("Got mouse release without being pressed."); + } + isPressed = false; + } + + public void mouseEntered(MouseEvent ev) { + recordEv(ev); + Point mousePt = ev.getPoint(); + Component comp = (Component) ev.getSource(); + Dimension size = comp.getSize(); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= size.width && + mousePt.y >= 0 && mousePt.y <= size.height); + + if (!inBounds) { + failure("Got mouse entered, but mouse not inside component."); + } + } + + public void mouseExited(MouseEvent ev) { + recordEv(ev); + Point mousePt = ev.getPoint(); + Component comp = (Component) ev.getSource(); + if (comp instanceof Frame) { + return; + } + Dimension size = comp.getSize(); + boolean isOnChild = (comp != comp.getComponentAt(mousePt)); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= size.width && + mousePt.y >= 0 && mousePt.y <= size.height); + if (!isOnChild && inBounds) { + failure("Got mouse exit, but mouse still inside component."); + } + } + + public void mouseDragged(MouseEvent ev) { + recordEv(ev); + if (!isPressed) { + failure("Got drag without a press first."); + } + } + + public void mouseMoved(MouseEvent ev) { + recordEv(ev); + } +} From 57c859e4adfedc963b1f4b3bf066453ace41ee36 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 8 Oct 2024 06:33:22 +0000 Subject: [PATCH 16/16] 8339836: Open source several AWT Mouse tests - Batch 1 Reviewed-by: honkar, prr --- .../java/awt/Mouse/MouseEnterExitTest.java | 174 ++++++++++++++++++ .../java/awt/Mouse/MouseEnterExitTest2.java | 140 ++++++++++++++ .../java/awt/Mouse/MouseEnterExitTest3.java | 84 +++++++++ .../java/awt/Mouse/MouseEnterExitTest4.java | 96 ++++++++++ test/jdk/java/awt/Mouse/MousePressedTest.java | 87 +++++++++ 5 files changed, 581 insertions(+) create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest.java create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest2.java create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest3.java create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest4.java create mode 100644 test/jdk/java/awt/Mouse/MousePressedTest.java diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java new file mode 100644 index 00000000000..059ad5c0548 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Robot; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @bug 4050138 + * @key headful + * @summary Test to verify Lightweight components don't get + * enter/exit during drags + * @run main MouseEnterExitTest + */ + +class LWSquare extends Container { + int width; + int height; + + public LWSquare(Color color, int w, int h) { + setBackground(color); + setLayout(new FlowLayout()); + width = w; + height = h; + addMouseListener(new EnterExitAdapter(this)); + setName("LWSquare-" + color.toString()); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getSize().width, getSize().height); + super.paint(g); + } + + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + + public Cursor getCursor() { + return new Cursor(Cursor.CROSSHAIR_CURSOR); + } +} + +class MouseFrame extends Frame { + public LWSquare lw; + + public MouseFrame() { + super("MouseEnterExitTest"); + setLayout(new FlowLayout()); + + lw = new LWSquare(Color.red, 75, 75); + add(lw); + setBounds(50, 50, 300, 200); + setVisible(true); + System.out.println(getInsets()); + + addMouseListener(new EnterExitAdapter(this)); + addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + dispose(); + } + } + ); + addKeyListener( + new KeyAdapter() { + public void keyPressed(KeyEvent ev) { + MouseEnterExitTest.getFrame().setTitle("MouseEnterExitTest"); + } + } + ); + } +} + + +public class MouseEnterExitTest { + static MouseFrame testFrame; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> testFrame = new MouseFrame()); + if (testFrame.lw.getBackground() != Color.red) { + throw new RuntimeException("Initial Background color not matching"); + } + robot.waitForIdle(); + robot.delay(100); + EventQueue.invokeAndWait(() -> robot.mouseMove( + testFrame.getLocationOnScreen().x + testFrame.getSize().width / 2, + testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(100); + + if (testFrame.lw.getBackground() != Color.green) { + throw new RuntimeException("Initial Background color not matching"); + } + EventQueue.invokeAndWait(() -> robot.mouseMove( + testFrame.getLocationOnScreen().x + testFrame.getSize().width * 2, + testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(100); + + if (testFrame.lw.getBackground() != Color.red) { + throw new RuntimeException("Initial Background color not matching"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (testFrame != null) { + testFrame.dispose(); + } + }); + } + } + + public static Frame getFrame() { + return testFrame; + } +} + +class EnterExitAdapter extends MouseAdapter { + Component compToColor; + Color colorNormal; + + EnterExitAdapter(Component comp) { + compToColor = comp; + colorNormal = comp.getBackground(); + } + + public void mouseEntered(MouseEvent ev) { + compToColor.setBackground(Color.green); + compToColor.repaint(); + } + + public void mouseExited(MouseEvent ev) { + compToColor.setBackground(colorNormal); + compToColor.repaint(); + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java new file mode 100644 index 00000000000..e09ac333447 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/* + * @test + * @bug 4150851 + * @summary Tests enter and exit events when a lightweight component is on a border + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseEnterExitTest2 + */ + +public class MouseEnterExitTest2 { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Verify that white component turns black whenever mouse enters the frame, + except when it enters the red rectangle. + 2. When the mouse enters the red part of the frame the component should stay white. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(EntryExitTest.initialize()) + .build() + .awaitAndCheck(); + } +} + +class EntryExitTest extends Component { + boolean inWin; + + public Dimension getPreferredSize() { + return new Dimension(200, 150); + } + + public void paint(Graphics g) { + Color c1, c2; + String s; + if (inWin) { + c1 = Color.black; + c2 = Color.white; + s = "IN"; + } else { + c2 = Color.black; + c1 = Color.white; + s = "OUT"; + } + g.setColor(c1); + Rectangle r = getBounds(); + g.fillRect(0, 0, r.width, r.height); + g.setColor(c2); + g.drawString(s, r.width / 2, r.height / 2); + } + + public static Frame initialize() { + EntryExitTest test = new EntryExitTest(); + MouseListener frameEnterExitListener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + test.inWin = true; + test.repaint(); + } + + public void mouseExited(MouseEvent e) { + test.inWin = false; + test.repaint(); + } + }; + + Frame f = new Frame("Mouse Modifier Test"); + + f.add(test); + Component jc = new Component() { + public Dimension getPreferredSize() { + return new Dimension(100, 50); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.red); + g.fillRect(0, 0, d.width, d.height); + } + }; + final Container cont = new Container() { + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } + }; + cont.setLayout(new GridLayout(2, 1)); + cont.add(jc); + jc.addMouseListener(new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + //System.out.println("Component entered"); + } + public void mouseExited(MouseEvent e) { + //System.out.println("Component exited"); + } + }); + + f.add(cont, BorderLayout.NORTH); + f.addMouseListener(frameEnterExitListener); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java new file mode 100644 index 00000000000..d5096d7acf0 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.JButton; + +/* + * @test + * @bug 4431868 + * @summary Tests that hw container doesn't receive mouse enter/exit events when mouse + * is moved between its lw and hw children + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseEnterExitTest3 + */ + +public class MouseEnterExitTest3 { + static final Button button = new Button("Button"); + static final JButton jbutton = new JButton("JButton"); + static final Frame frame = new Frame("Mouse Enter/Exit Test"); + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Move the mouse between Button and JButton + 2. Verify that the frame doesn't receive enter/exit events + (Enter/exit events are dumped to the area below) + 4. If you see enter/exit events dumped the test fails + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(4) + .build() + .awaitAndCheck(); + } + + final static MouseListener listener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log(e.toString()); + } + + public void mouseExited(MouseEvent e) { + PassFailJFrame.log(e.toString()); + } + }; + + public static Frame initialize() { + frame.setLayout(new GridLayout(2, 1)); + frame.add(button); + frame.add(jbutton); + frame.addMouseListener(listener); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java new file mode 100644 index 00000000000..2ee3993ae4e --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/* + * @test + * @bug 4431868 + * @key headful + * @summary Tests that window totally obscured by its child doesn't receive + * enter/exit events when located over another frame + * @run main MouseEnterExitTest4 + */ + +public class MouseEnterExitTest4 { + static Button button = new Button("Button"); + static Frame frame = new Frame("Mouse Enter/Exit test"); + static Window window = new Window(frame); + static MouseListener listener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + throw new RuntimeException("Test failed due to Mouse Enter event"); + } + + public void mouseExited(MouseEvent e) { + throw new RuntimeException("Test failed due to Mouse Exit event"); + } + }; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + button.setBackground(Color.red); + window.add(button); + frame.setBounds(100, 100, 300, 300); + window.setBounds(200, 200, 100, 100); + window.addMouseListener(listener); + window.setVisible(true); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(200); + EventQueue.invokeAndWait(() -> robot.mouseMove( + frame.getLocationOnScreen().x + frame.getSize().width / 2, + frame.getLocationOnScreen().y + frame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(200); + EventQueue.invokeAndWait(() -> robot.mouseMove( + window.getLocationOnScreen().x + window.getSize().width * 2, + window.getLocationOnScreen().y + window.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(500); + System.out.println("Test Passed"); + + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + if (window != null) { + window.dispose(); + } + }); + } + } +} diff --git a/test/jdk/java/awt/Mouse/MousePressedTest.java b/test/jdk/java/awt/Mouse/MousePressedTest.java new file mode 100644 index 00000000000..721d69bd5dd --- /dev/null +++ b/test/jdk/java/awt/Mouse/MousePressedTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Container; +import java.awt.GridLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JToggleButton; + +/* + * @test + * @bug 4268759 + * @summary Tests whether clicking on the edge of a lightweight button + * causes sticking behavior + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MousePressedTest + */ + +public class MousePressedTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click and hold on the very bottom border (2-pixel-wide border) of the + JButton. Then drag the mouse straight down out of the JButton and + into the JRadioButton, and release the mouse button + 2. If the component remains highlighted as if the mouse button is still + down, the test fails + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static JFrame initialize() { + JFrame f = new JFrame("JButton Test"); + JPanel p = new JPanel(); + p.setLayout(new GridLayout(2, 2)); + JButton b = new JButton("JButton"); + p.add(b); + JCheckBox cb = new JCheckBox("JCheckBox"); + p.add(cb); + JRadioButton rb = new JRadioButton("JRadioButton"); + p.add(rb); + p.add(new JToggleButton("JToggleButton")); + + JScrollPane j = new JScrollPane(p, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + Container c = f.getContentPane(); + c.setLayout(new GridLayout(1, 1)); + c.add(j); + f.pack(); + return f; + } +}