diff --git a/.github/actions/build-occt/action.yml b/.github/actions/build-occt/action.yml index b503d2ac9a..bdd11d9085 100644 --- a/.github/actions/build-occt/action.yml +++ b/.github/actions/build-occt/action.yml @@ -78,7 +78,7 @@ runs: shell: bash - name: Upload install directory - uses: actions/upload-artifact@v4.6.2 + uses: ./.github/actions/upload-artifacts with: name: ${{ inputs.artifact-name }} path: install diff --git a/.github/actions/build-sample-csharp/action.yml b/.github/actions/build-sample-csharp/action.yml index c73bdf8f00..1f02efb0ad 100644 --- a/.github/actions/build-sample-csharp/action.yml +++ b/.github/actions/build-sample-csharp/action.yml @@ -13,7 +13,7 @@ runs: using: "composite" steps: - name: Download OCCT installation - uses: actions/download-artifact@v4.3.0 + uses: ./.github/actions/download-artifacts with: name: ${{ inputs.install-artifact-name }} path: occt-install diff --git a/.github/actions/build-sample-mfc/action.yml b/.github/actions/build-sample-mfc/action.yml index b16465dde0..e4103b2415 100644 --- a/.github/actions/build-sample-mfc/action.yml +++ b/.github/actions/build-sample-mfc/action.yml @@ -13,7 +13,7 @@ runs: using: "composite" steps: - name: Download OCCT installation - uses: actions/download-artifact@v4.3.0 + uses: ./.github/actions/download-artifacts with: name: ${{ inputs.install-artifact-name }} path: occt-install diff --git a/.github/actions/build-sample-qt/action.yml b/.github/actions/build-sample-qt/action.yml index 5133fe5d18..c910d6829d 100644 --- a/.github/actions/build-sample-qt/action.yml +++ b/.github/actions/build-sample-qt/action.yml @@ -17,7 +17,7 @@ runs: using: "composite" steps: - name: Download OCCT installation - uses: actions/download-artifact@v4.3.0 + uses: ./.github/actions/download-artifacts with: name: ${{ inputs.install-artifact-name }} path: occt-install diff --git a/.github/actions/build-tinspector/action.yml b/.github/actions/build-tinspector/action.yml index a3891605df..bade453104 100644 --- a/.github/actions/build-tinspector/action.yml +++ b/.github/actions/build-tinspector/action.yml @@ -17,7 +17,7 @@ runs: using: "composite" steps: - name: Download OCCT installation - uses: actions/download-artifact@v4.3.0 + uses: ./.github/actions/download-artifacts with: name: ${{ inputs.install-artifact-name }} path: occt-install diff --git a/.github/actions/download-artifacts/action.yml b/.github/actions/download-artifacts/action.yml new file mode 100644 index 0000000000..220ca71fde --- /dev/null +++ b/.github/actions/download-artifacts/action.yml @@ -0,0 +1,109 @@ +name: 'Download Platform Artifacts' +description: 'Download and extract artifacts with proper file permissions and symlinks (cross-platform)' +inputs: + name: + description: 'Artifact name' + required: true + path: + description: 'Path to extract to (optional)' + required: false + default: '.' + +runs: + using: 'composite' + steps: + - name: Download archive + uses: actions/download-artifact@v4.3.0 + with: + name: ${{ inputs.name }} + path: ./download-temp + + - name: Extract archive (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $EXTRACT_PATH = "${{ inputs.path }}" + $ARCHIVE_FILE = "./download-temp/${{ inputs.name }}.zip" + + if (-not (Test-Path $ARCHIVE_FILE)) { + Write-Error "Archive file $ARCHIVE_FILE not found" + Get-ChildItem ./download-temp/ + exit 1 + } + + Write-Output "Extracting $ARCHIVE_FILE to $EXTRACT_PATH" + + # Extract and handle directory structure properly + if ($EXTRACT_PATH -ne ".") { + # Extract to temp location first + New-Item -ItemType Directory -Path "temp-extract" -Force | Out-Null + Expand-Archive -Path $ARCHIVE_FILE -DestinationPath "temp-extract" -Force + + # Move the extracted content to the desired path + if (Test-Path "temp-extract/install") { + # Remove target directory if it exists to avoid nesting + if (Test-Path $EXTRACT_PATH) { + Remove-Item -Recurse -Force $EXTRACT_PATH + } + Move-Item "temp-extract/install" $EXTRACT_PATH -Force + } else { + # If archive doesn't contain install/, move everything + New-Item -ItemType Directory -Path $EXTRACT_PATH -Force | Out-Null + Get-ChildItem "temp-extract" | Move-Item -Destination $EXTRACT_PATH -Force + } + + # Clean up temp directory + Remove-Item -Recurse -Force "temp-extract" + } else { + Expand-Archive -Path $ARCHIVE_FILE -DestinationPath $EXTRACT_PATH -Force + } + + Write-Output "Extraction complete" + Get-ChildItem $EXTRACT_PATH -ErrorAction SilentlyContinue + + # Clean up temporary download directory + Remove-Item -Recurse -Force ./download-temp + + - name: Extract archive (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + EXTRACT_PATH="${{ inputs.path }}" + ARCHIVE_FILE="./download-temp/${{ inputs.name }}.tar.gz" + + if [ ! -f "$ARCHIVE_FILE" ]; then + echo "Error: Archive file $ARCHIVE_FILE not found" + ls -la ./download-temp/ + exit 1 + fi + + echo "Extracting $ARCHIVE_FILE to $EXTRACT_PATH" + + # Extract and handle directory structure properly + if [ "$EXTRACT_PATH" != "." ]; then + # Extract to temp location first + mkdir -p temp-extract + tar -xzf "$ARCHIVE_FILE" -C temp-extract + + # Move the extracted content to the desired path + if [ -d "temp-extract/install" ]; then + # Remove target directory if it exists to avoid nesting + rm -rf "$EXTRACT_PATH" + mv "temp-extract/install" "$EXTRACT_PATH" + else + # If archive doesn't contain install/, move everything + mkdir -p "$EXTRACT_PATH" + mv temp-extract/* "$EXTRACT_PATH/" + fi + + # Clean up temp directory + rm -rf temp-extract + else + tar -xzf "$ARCHIVE_FILE" -C "$EXTRACT_PATH" + fi + + echo "Extraction complete" + ls -la "$EXTRACT_PATH" + + # Clean up temporary download directory + rm -rf ./download-temp \ No newline at end of file diff --git a/.github/actions/retest-failures/action.yml b/.github/actions/retest-failures/action.yml index 80b2506389..d18673a488 100644 --- a/.github/actions/retest-failures/action.yml +++ b/.github/actions/retest-failures/action.yml @@ -118,7 +118,7 @@ runs: - name: Download and extract install directory if: steps.check_failures.outputs.failed_count > 0 - uses: actions/download-artifact@v4.3.0 + uses: ./.github/actions/download-artifacts with: name: ${{ inputs.install-artifact-name }} path: install diff --git a/.github/actions/run-gtest/action.yml b/.github/actions/run-gtest/action.yml index 9b8fc4af15..44aab0ead6 100644 --- a/.github/actions/run-gtest/action.yml +++ b/.github/actions/run-gtest/action.yml @@ -25,7 +25,7 @@ runs: using: "composite" steps: - name: Download and extract install directory - uses: actions/download-artifact@v4.3.0 + uses: ./.github/actions/download-artifacts with: name: ${{ inputs.install-artifact-name }} path: install diff --git a/.github/actions/run-tests/action.yml b/.github/actions/run-tests/action.yml index 3d9f74f065..1d45559fcb 100644 --- a/.github/actions/run-tests/action.yml +++ b/.github/actions/run-tests/action.yml @@ -53,7 +53,7 @@ runs: shell: bash - name: Download and extract install directory - uses: actions/download-artifact@v4.3.0 + uses: ./.github/actions/download-artifacts with: name: ${{ inputs.install-artifact-name }} path: install diff --git a/.github/actions/testgrid/testmacos.tcl b/.github/actions/testgrid/testmacos.tcl index d33da8fdd3..782a44bc22 100644 --- a/.github/actions/testgrid/testmacos.tcl +++ b/.github/actions/testgrid/testmacos.tcl @@ -1 +1 @@ -testgrid -outdir results/macos-x64 caf basic \ No newline at end of file +testgrid -outdir results/macos-x64 "caf,helix" "basic,standard" \ No newline at end of file diff --git a/.github/actions/upload-artifacts/action.yml b/.github/actions/upload-artifacts/action.yml new file mode 100644 index 0000000000..96bf267b95 --- /dev/null +++ b/.github/actions/upload-artifacts/action.yml @@ -0,0 +1,58 @@ +name: 'Upload Platform Artifacts' +description: 'Upload artifacts with proper file permissions and symlinks (cross-platform)' +inputs: + name: + description: 'Artifact name' + required: true + path: + description: 'Path to archive' + required: true + retention-days: + description: 'Number of days to retain artifact' + required: false + default: '30' + +runs: + using: 'composite' + steps: + - name: Create archive (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $BASE_PATH = "${{ inputs.path }}" + $ARCHIVE_NAME = "${{ inputs.name }}.zip" + + if (Test-Path $BASE_PATH -PathType Container) { + Compress-Archive -Path $BASE_PATH -DestinationPath $ARCHIVE_NAME + Write-Output "Created archive: $ARCHIVE_NAME" + Get-ChildItem $ARCHIVE_NAME + } else { + Write-Error "Error: Path $BASE_PATH does not exist" + exit 1 + } + + - name: Create archive (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + BASE_PATH="${{ inputs.path }}" + ARCHIVE_NAME="${{ inputs.name }}.tar.gz" + + if [ -d "$BASE_PATH" ]; then + tar -czf "$ARCHIVE_NAME" -C "$(dirname "$BASE_PATH")" "$(basename "$BASE_PATH")" + elif [ -f "$BASE_PATH" ]; then + tar -czf "$ARCHIVE_NAME" -C "$(dirname "$BASE_PATH")" "$(basename "$BASE_PATH")" + else + echo "Error: Path $BASE_PATH does not exist" + exit 1 + fi + + echo "Created archive: $ARCHIVE_NAME" + ls -la "$ARCHIVE_NAME" + + - name: Upload archive + uses: actions/upload-artifact@v4.6.2 + with: + name: ${{ inputs.name }} + path: ${{ inputs.name }}.* + retention-days: ${{ inputs.retention-days }} \ No newline at end of file diff --git a/src/Draw/TKDraw/Draw/Draw_Window_1.mm b/src/Draw/TKDraw/Draw/Draw_Window_1.mm index b2a194ac2f..8bde15f7d1 100644 --- a/src/Draw/TKDraw/Draw/Draw_Window_1.mm +++ b/src/Draw/TKDraw/Draw/Draw_Window_1.mm @@ -175,6 +175,24 @@ static Standard_Integer getScreenBottom() { Cocoa_LocalPool aLocalPool; + // pre-warm graphics context to avoid Metal initialization issues + static bool isGraphicsInitialized = false; + if (!isGraphicsInitialized) + { + @try + { + NSImage* anInitImage = [[NSImage alloc] initWithSize: NSMakeSize (1, 1)]; + [anInitImage lockFocus]; + [anInitImage unlockFocus]; + [anInitImage release]; + } + @catch (NSException*) + { + // ignore initialization exceptions + } + isGraphicsInitialized = true; + } + // converting left-bottom coordinate to left-top coordinate Standard_Integer anYTop = getScreenBottom() - theXY.y() - theSize.y(); @@ -519,37 +537,68 @@ static Standard_Integer getScreenBottom() //function : Save //purpose : //======================================================================= -Standard_Boolean Draw_Window::Save (Standard_CString theFileName) const +bool Draw_Window::Save (Standard_CString theFileName) const { - Cocoa_LocalPool aLocalPool; - - NSString* aFileName = [[[NSString alloc] initWithUTF8String: theFileName] autorelease]; - NSString* aFileExtension = [[aFileName pathExtension] lowercaseString]; - - NSDictionary* aFileTypeDict = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt: NSBitmapImageFileTypePNG], @"png", - [NSNumber numberWithInt: NSBitmapImageFileTypeBMP], @"bmp", - [NSNumber numberWithInt: NSBitmapImageFileTypeJPEG], @"jpg", - [NSNumber numberWithInt: NSBitmapImageFileTypeGIF], @"gif", - nil]; - if ([aFileTypeDict valueForKey: aFileExtension] == NULL) + if (myImageBuffer == NULL || theFileName == NULL) { - return Standard_False; // unsupported image extension + return false; } - NSBitmapImageFileType aFileType = (NSBitmapImageFileType )[[aFileTypeDict valueForKey: aFileExtension] intValue]; - NSBitmapImageRep* anImageRep = [NSBitmapImageRep imageRepWithData: [myImageBuffer TIFFRepresentation]]; - - NSDictionary* anImgProps = [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 0.8] - forKey: NSImageCompressionFactor]; - - NSData* aData = [anImageRep representationUsingType: aFileType - properties: anImgProps]; - - Standard_Boolean isSuccess = [aData writeToFile: aFileName - atomically: NO]; + Cocoa_LocalPool aLocalPool; - return isSuccess; + @try + { + NSString* aFileName = [[[NSString alloc] initWithUTF8String: theFileName] autorelease]; + NSString* aFileExtension = [[aFileName pathExtension] lowercaseString]; + + NSDictionary* aFileTypeDict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt: NSBitmapImageFileTypePNG], @"png", + [NSNumber numberWithInt: NSBitmapImageFileTypeBMP], @"bmp", + [NSNumber numberWithInt: NSBitmapImageFileTypeJPEG], @"jpg", + [NSNumber numberWithInt: NSBitmapImageFileTypeGIF], @"gif", + nil]; + if ([aFileTypeDict valueForKey: aFileExtension] == NULL) + { + return false; + } + + NSBitmapImageFileType aFileType = (NSBitmapImageFileType )[[aFileTypeDict valueForKey: aFileExtension] intValue]; + + // Ensure image buffer is properly locked before accessing + [myImageBuffer lockFocus]; + [myImageBuffer unlockFocus]; + + NSData* aTiffData = [myImageBuffer TIFFRepresentation]; + if (aTiffData == NULL) + { + return false; + } + + NSBitmapImageRep* anImageRep = [NSBitmapImageRep imageRepWithData: aTiffData]; + if (anImageRep == NULL) + { + return false; + } + + NSDictionary* anImgProps = [NSDictionary dictionaryWithObject: [NSNumber numberWithFloat: 0.8] + forKey: NSImageCompressionFactor]; + + NSData* aData = [anImageRep representationUsingType: aFileType + properties: anImgProps]; + if (aData == NULL) + { + return false; + } + + bool isSuccess = [aData writeToFile: aFileName + atomically: NO]; + + return isSuccess; + } + @catch (NSException*) + { + return false; + } } Standard_Boolean Draw_Window::IsEqualWindows (const long theWindowNumber)