DisplayEvents

Demontrates how to handle notifications about display change when programming with ADLX.

Sample Path

/Samples/CPP/Display/DisplayEvents

Code

Copied!

//
// Copyright (c) 2021 - 2024 Advanced Micro Devices, Inc. All rights reserved.
//
//-------------------------------------------------------------------------------------------------


#include "SDK/ADLXHelper/Windows/Cpp/ADLXHelper.h"
#include "SDK/Include/IDisplay3DLUT.h"
#include "SDK/Include/IDisplayGamma.h"
#include "SDK/Include/IDisplayGamut.h"
#include "SDK/Include/IDisplays.h"
#include <iostream>
#include <string>
#include <thread>

// Use ADLX namespace
using namespace adlx;

// ADLXHelper instance
// No outstanding interfaces from ADLX must exist when ADLX is destroyed.
// Use global variables to ensure validity of the interface.
static ADLXHelper g_ADLXHelp;

// Callback for displayListChanged
class DisplayListChangedCallBack : public IADLXDisplayListChangedListener
{
public:
    adlx_bool ADLX_STD_CALL OnDisplayListChanged(IADLXDisplayList* pNewDisplays) override
    {
        std::cout << "Display list has been changed" << std::endl;

        // If true is returned ADLX continues to notify next listener else if false is retuned ADLX stops the notification.
        return true;
    }
};

// Callback for displayGamutChanged
class DisplayGamutCallBack : public IADLXDisplayGamutChangedListener
{
public:
    adlx_bool ADLX_STD_CALL OnDisplayGamutChanged(IADLXDisplayGamutChangedEvent* pDisplayGamutChangedEvent) override
    {
        std::cout << "Display gamut is changed" << std::endl;
        // If true is returned ADLX continues to notify next listener else if false is retuned ADLX stops the notification.
        return true;
    }
};

// Callback for displayGammaChanged
class DisplayGammaCallBack : public IADLXDisplayGammaChangedListener
{
public:
    adlx_bool ADLX_STD_CALL OnDisplayGammaChanged(IADLXDisplayGammaChangedEvent* pDisplayGammaChangedEvent) override
    {
        std::cout << "Display gamma is changed" << std::endl;

        IADLXDisplayPtr display;
        ADLX_RESULT  res = pDisplayGammaChangedEvent->GetDisplay(&display);
        if (ADLX_SUCCEEDED (res))
        {
            const char* displayName = nullptr;
            display->Name(&displayName);
            adlx_bool changed = pDisplayGammaChangedEvent->IsDeGammaChanged();
            std::cout << "\\tDisplay: " << displayName << " DeGamma changed: " << changed << std::endl;
            changed = pDisplayGammaChangedEvent->IsReGammaChanged();
            std::cout << "\\tDisplay: " << displayName << " ReGamma changed: " << changed << std::endl;
            changed = pDisplayGammaChangedEvent->IsGammaCoefficientChanged();
            std::cout << "\\tDisplay: " << displayName << " Gamma Coefficient changed: " << changed << std::endl;
            changed = pDisplayGammaChangedEvent->IsGammaRampChanged();
            std::cout << "\\tDisplay: " << displayName << " Gamma Ramp changed: " << changed << std::endl;
        }
        // If true is returned ADLX continues to notify next listener else if false is retuned ADLX stops the notification.
        return true;
    }
};

// Callback for display3DLUT
class Display3DLUTCallBack : public IADLXDisplay3DLUTChangedListener
{
public:
    adlx_bool ADLX_STD_CALL OnDisplay3DLUTChanged(IADLXDisplay3DLUTChangedEvent* pDisplay3DLUTChangedEvent) override
    {
        std::cout << "Display 3DLUT is changed" << std::endl;
        // If true is returned ADLX continues to notify next listener else if false is retuned ADLX stops the notification.
        return true;
    }
};

// Loop thread
void LoopThread();

// Wait for exit with error message
int WaitAndExit(const char* msg, const int retCode);

int main()
{
    // Define return code
    ADLX_RESULT  res = ADLX_FAIL ;

    // Initialize ADLX
    res = g_ADLXHelp.Initialize();
    if (ADLX_SUCCEEDED (res))
    {
        // Get display services
        IADLXDisplayServicesPtr displayService;
        res = g_ADLXHelp.GetSystemServices()->GetDisplaysServices(&displayService);
        if (ADLX_SUCCEEDED (res))
        {
            // Get display change handler
            IADLXDisplayChangedHandlingPtr displayChangeHandler;
            res = displayService->GetDisplayChangedHandling(&displayChangeHandler);
            if (ADLX_FAILED (res))
                return WaitAndExit("Failed to get display change handler", 0);

            // Create the callbacks
            IADLXDisplayListChangedListener* listChangeCallBack = new DisplayListChangedCallBack;
            IADLXDisplayGammaChangedListener* gammaChangeCallBack = new DisplayGammaCallBack;
            IADLXDisplayGamutChangedListener* gamutChangeCallBack = new DisplayGamutCallBack;
            IADLXDisplay3DLUTChangedListener* display3DLUTChangeCallBack = new Display3DLUTCallBack;

            // Add the callbacks to the ADLX event handler
            {
                displayChangeHandler->AddDisplayListEventListener(listChangeCallBack);
                displayChangeHandler->AddDisplayGammaEventListener(gammaChangeCallBack);
                displayChangeHandler->AddDisplayGamutEventListener(gamutChangeCallBack);
                displayChangeHandler->AddDisplay3DLUTEventListener(display3DLUTChangeCallBack);
            }

            // Create loop thread for wait event
            std::thread loop(&LoopThread);
            loop.join();

            // Remove and destroy callbacks
            displayChangeHandler->RemoveDisplayGamutEventListener(gamutChangeCallBack);
            displayChangeHandler->RemoveDisplayListEventListener(listChangeCallBack);
            displayChangeHandler->RemoveDisplay3DLUTEventListener(display3DLUTChangeCallBack);
            displayChangeHandler->RemoveDisplayGammaEventListener(gammaChangeCallBack);

            delete listChangeCallBack;
            listChangeCallBack = nullptr;
            delete gamutChangeCallBack;
            gamutChangeCallBack = nullptr;
            delete gammaChangeCallBack;
            gammaChangeCallBack = nullptr;
            delete display3DLUTChangeCallBack;
            display3DLUTChangeCallBack = nullptr;
        }
        else
        {
            // Destroy ADLX
            res = g_ADLXHelp.Terminate();
            std::cout << "Destroy ADLX result: " << res << std::endl;
            return WaitAndExit("Failed to get display services", 0);
        }
    }
    else
    {
        return WaitAndExit("ADLX initialization failed", 0);
    }

    // Destroy ADLX
    res = g_ADLXHelp.Terminate();
    std::cout << "Destroy ADLX result: " << res << std::endl;

    // Pause to see the printout
    system("pause");

    return 0;
}

// Loop thread
void LoopThread()
{
    std::cout << "Loop thread is currently running." << std::endl;
    std::cout << "-> Plug or unplug the display to trigger DisplayListChange, which will further trigger other changes." << std::endl;
    std::cout << "->Press Q/q to terminate the loop." << std::endl;
    int num = 0;
    std::chrono::seconds dura(1);
    while ((num = getchar()) != 'q' && num != 'Q')
    {
        std::cout << "Wait for the event to get triggered. The display can be pluged or unpluged to trigger DisplayListChange." << std::endl;
        std::this_thread::sleep_for(dura);
        num = getchar();
        if (num == 'q' || num == 'Q')
            break;
    }
}

// Wait for exit with error message
int WaitAndExit(const char* msg, const int retCode)
{
    // Printout the message and pause to see it before returning the desired code
    if (nullptr != msg)
        std::cout << msg << std::endl;

    system("pause");
    return retCode;
}