Results 1 to 5 of 5

Thread: OS/X how to get physical display handle

  1. #1
    Join Date
    Mar 2006
    Posts
    74
    Thanks
    1
    Qt products
    Qt3
    Platforms
    MacOS X Unix/X11 Windows

    Default OS/X how to get physical display handle

    I need to be able to manipulate the video card gamma tables in my cross platform application. This code needs to be able to do this for each display on multi-display systems based on the location of the dialog that the user is interacting with. I have this working on X11 and Windows and on OS/X the code is far enough along that it will manipulate the gamma table of CGMainDisplayID but I have been unable to find any documentation or any other source on how to get from something I can get from Qt such as QDesktopWidget::screenNumber() or this -> winID() to a handle that can be used to manipulate the video card gamma for a specific display.

    The code in my dialog looks like this:

    Qt Code:
    1. #if defined (Q_WS_WIN)
    2. screen = (int) this -> winId ();
    3. #elif defined(Q_WS_MAC) // FIXME
    4. screen = (int) this -> winId ();
    5. #elif defined(Q_WS_X11) // this is an X11 system
    6. screen = desktop -> screenNumber(pixmapColor -> mapToGlobal(pixmapColor -> pos()));
    7. #else
    8. #error "Your system is not supported yet. The video gamma setting code will need to be updated to support your system."
    9. #endif[
    10.  
    11. gamma_ramp gammaRamp = new gamma_ramp(screen);
    12. gammaRamp->setGammaRamp();
    13. ...
    To copy to clipboard, switch view to plain text mode 


    For X11 this is very simple to use as the above boils down to a call to XF86VidModeGetGammaRamp(...) where the screenNumber value is passed in as the second parameter. On Windows it is a little more involved since winID needs to be translated into a handle and the called code looks looks like this:

    Qt Code:
    1. void gamma_ramp::getGammaRamp()
    2. {
    3. HDC hDisplayDC;
    4. HRESULT hr;
    5.  
    6. hDisplayDC = GetDCEx((HWND) screen, 0, DCX_CLIPSIBLINGS|DCX_CACHE);
    7. hr = GetDeviceGammaRamp(hDisplayDC, (LPVOID) ramp_buffer);
    8. ReleaseDC((HWND) screen, hDisplayDC);
    9.  
    10. this -> convertPrivShort2ramp_type();
    11. }
    To copy to clipboard, switch view to plain text mode 

    This is much closer to what needs to happen on OS/X where the code currently looks like this:

    Qt Code:
    1. void gamma_ramp::getGammaRamp()
    2. {
    3. CGTableCount count;
    4. CGDisplayErr error_code;
    5.  
    6. // FIXME only does the main display
    7. CGDirectDisplayID dspID = CGMainDisplayID();
    8.  
    9. error_code = CGGetDisplayTransferByTable (dspID,
    10. (CGTableCount) size,
    11. &ramp_buffer[0],
    12. &ramp_buffer[size],
    13. &ramp_buffer[size*2],
    14. &count);
    15.  
    16. for (int i=0; i < size; ++i)
    17. {
    18. red[i] = interpol(ramp_buffer, i, size, count);
    19. green[i] = interpol(ramp_buffer + size, i, size, count);
    20. blue[i] = interpol(ramp_buffer + size*2, i, size, count);
    21. }
    22. }
    To copy to clipboard, switch view to plain text mode 

    As you can see currently the OS/X code only uses the main display:

    Qt Code:
    1. CGDirectDisplayID dspID = CGMainDisplayID();
    To copy to clipboard, switch view to plain text mode 

    What I need is a way to get from winID(), screenNumber() or something that is Qt supplied to a CGDirectDisplayID and I have been desperately looking for anything about how to do this. Anything about this would be helpful such as a possible source of documentation or perhaps a link to a forum that specializes in Qt OS/X. Even the programmer who worked on the OS/X code didn't have any idea how to handle this and he works on a large Qt open source project. I should add that he did get this code to the point where it builds and will work on the main display gamma table. So I am very grateful for his efforts.

  2. #2
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: OS/X how to get physical display handle

    I'm not sure if you can do this solely with qt, but have you looked into what CVDisplayLinkCreateWithActiveCGDisplays&friends can do?
    It returns a display link associated with all the active display. Therefore if you alter this link( gamma, or whatever), you alter all the displays.

    Here are the links too:
    http://developer.apple.com/documenta...tiveCGDisplays
    Some samples:
    http://developer.apple.com/documenta...section_2.html

    Regards

  3. #3
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: OS/X how to get physical display handle

    Oh, and of course, this is how you get the active display list and their respective IDs:
    http://developer.apple.com/documenta...0-CH202-251664

    Each physical display has an unique ID associated with it( by Quartz I think ). So if you get these, then you can get thei CGDirectDisplayIDs.

    Actually, I think it is pretty clear:
    CGGetActiveDisplayList
    Provides a list of displays that are active (or drawable).
    CGDisplayErr CGGetActiveDisplayList (
    CGDisplayCount maxDisplays,
    CGDirectDisplayID * displays,
    CGDisplayCount * displayCount
    );
    Parameters
    maxDisplays
    The size of the displays array. This value determines the maximum number of displays that can be returned.
    displays
    A pointer to storage provided by the caller for an array of display IDs. On return, this storage contains a list of active displays.
    displayCount
    A pointer to a CGDisplayCount variable provided by the caller. On return, the variable contains the actual number of displays returned in the displays array. If displays is NULL, this variable contains the total number of active displays.
    Return Value
    A result code. See “Quartz Display Services Result Codes”.
    Discussion
    The first entry in the list of active displays is the main display. In case of mirroring, the first entry is the largest drawable display or, if all are the same size, the display with the greatest pixel depth.
    Availability
    • Available in Mac OS X version 10.0 and later.
    Declared In
    CGDirectDisplay.h
    Regards

  4. #4
    Join Date
    Mar 2006
    Posts
    74
    Thanks
    1
    Qt products
    Qt3
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: OS/X how to get physical display handle

    I found one source that says the following about OS/X:

    "In Qt 4, every widget is an HIView, so you calling winId() will
    return you the HIViewRef, you can then use Carbon functions like HIViewGetWindow() to get a WindowPtr.

    In Qt 3, you can get a WindowPtr by calling handle() on the top-level widget."

    But looking at the Qt3 docs I can't find handle() anywhere. So I don't trust this source. If it were correct once I had a WindowPtr I could call GetWindowBounds to get the coordinates for the window and then a call to either CGGetDisplaysWithPoint or CGGetDisplaysWithRect using the window coordinates should get the correct CGDirectDisplayID.

    This is frustrating since I found it fairly easy to find OK docs about this, meaning how to map either winId() or screenNumber() to get the native display handle, for both Windows and X11 and the complete absence of any information on how this should be programmed on OS/X is frustrating. In addition, I don't have a machine I can test any of this on so I have to work with other programmers who have access to an OS/X machine. If I had an OS/X machine I could play around with these things and figure out how to make it work. I would like to be able to say to the OS/X programmer "Look here and here ... for some information about how this can be handled." But what I have is not enough that I am willing to bother them with this at this point.

    I have a few more clues now about how this might be made to work. Your information was helpful. Maybe someone else here will see this and either confirm that the above is on the right track or that it is off base.

  5. #5
    Join Date
    Mar 2006
    Posts
    74
    Thanks
    1
    Qt products
    Qt3
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: OS/X how to get physical display handle

    For those interested in how this issue is solved I have this working. So I will post some code snippets.

    The header file looks like this:

    Qt Code:
    1. typedef double ramp_type;
    2.  
    3. #ifdef __WIN32__
    4. #include <windows.h>
    5. typedef unsigned short ramp_type_private;
    6. typedef HDC displayHandle;
    7. #elif defined (__APPLE__)
    8. #ifndef DEBUG
    9. #define DEBUG 0
    10. #endif
    11. #include <Carbon/Carbon.h>
    12. #include <CoreServices/CoreServices.h>
    13. #include <IOKit/Graphics/IOGraphicsLib.h>
    14. typedef CGGammaValue ramp_type_private;
    15. typedef CGDirectDisplayID displayHandle;
    16. #elif defined (UNIX)
    17. typedef unsigned short ramp_type_private;
    18. typedef int displayHandle;
    19. #else
    20. #error "no typedef for ramp_type_private and displayHandle are available for your platform"
    21. #endif
    22.  
    23. class gamma_ramp
    24. {
    25. public:
    26. int size;
    27. ramp_type *red, *green, *blue;
    28.  
    29. gamma_ramp(int screen, int leftIn, int topIn); // screen is ignored on OS/X and Windows
    30. // leftIn and topIn are ignored on X11
    31.  
    32. ~gamma_ramp();
    33. void getGammaRamp(); // returns size
    34. void setGammaRamp();
    35.  
    36. void setLinearGammaRamp();
    37.  
    38. private:
    39. int getGammaRampSize();
    40. void convertPrivShort2ramp_type();
    41. void convert_ramp_type2short();
    42.  
    43. ramp_type_private* ramp_buffer;
    44. int screen, left, top;
    45. displayHandle display;
    46. };
    To copy to clipboard, switch view to plain text mode 

    The main thing of interest is how the code gets the handle to the display device so that it manipulates the correct video card gamma table.

    For OS/X it looks like this:

    Qt Code:
    1. CGPoint point;
    2.  
    3. CGDirectDisplayID getDisplay()
    4. {
    5. const int maxDisplays = 64; // 64 should be enough for any system
    6. CGDisplayErr displayStatus;
    7. CGDisplayCount displayCount; // Total number of display IDs
    8. CGDirectDisplayID displayIDs[maxDisplays]; // Array of display IDs
    9.  
    10. displayStatus = CGGetDisplaysWithPoint ( point, maxDisplays, displayIDs, &displayCount);
    11. if (displayStatus != kCGErrorSuccess || displayCount!= 1)
    12. {
    13. printf("CGGetDisplaysWithPoint returned error or the wrong number of displays\n");
    14. return NULL;
    15. }
    16. else
    17. return displayIDs[0];
    18. }
    19.  
    20. gamma_ramp::gamma_ramp(int Screen, int leftIn, int topIn)
    21. {
    22. // screen = Screen;
    23. left = leftIn;
    24. top = topIn;
    25. point.y = float(top);
    26. point.x = float(left);
    27.  
    28. display = getDisplay();
    29. screen = 0;
    30. if (display == NULL)
    31. {
    32. ramp_buffer = 0;
    33. red = 0;
    34. green = 0;
    35. blue = 0;
    36. printf("gamma_ramp::gamma_ramp - error failed to get display handle");
    37. }
    38. else // do what needs to be done to set up the gamma tables
    39. }
    To copy to clipboard, switch view to plain text mode 

    On Windows it looks like this:

    Qt Code:
    1. static int numMatchingDisplays;
    2. static RECT clipRegion;
    3.  
    4. static BOOL CALLBACK MonitorEnumProc(
    5. HMONITOR hMonitor, // handle to display monitor
    6. HDC hdcMonitor, // NULL, because EnumDisplayMonitors hdc is NULL
    7. LPRECT displayCoordintes, // Virtual screen coordinates of this monitor
    8. LPARAM name // Context data used to pass back display name in our case
    9. )
    10. {
    11. MONITORINFOEX pmi;
    12.  
    13. if (displayCoordintes -> left <= clipRegion.left &&
    14. displayCoordintes -> bottom >= clipRegion.top &&
    15. displayCoordintes -> right >= clipRegion.left &&
    16. displayCoordintes -> top <= clipRegion.top)
    17. {
    18. // display contains the widget
    19. pmi.cbSize = sizeof(MONITORINFOEX);
    20. if (GetMonitorInfo(hMonitor, (MONITORINFO *)&pmi) == 0)
    21. {
    22. printf("MonitorEnumProc - get_displays failed GetMonitorInfo\n");
    23. return FALSE;
    24. }
    25. else // it worked we have the device we want
    26. {
    27. numMatchingDisplays++;
    28. return TRUE;
    29. }
    30. }
    31. else // this is OK as the device is not the one we want
    32. {
    33. return TRUE;
    34. }
    35. }
    36.  
    37. HDC getDisplay()
    38. {
    39.  
    40. BOOL (WINAPI* pEnumDisplayDevices)(PVOID,DWORD,PVOID,DWORD);
    41. char name[256];
    42. HDC dispHand;
    43.  
    44. pEnumDisplayDevices = (BOOL (WINAPI*)(PVOID,DWORD,PVOID,DWORD)) GetProcAddress(LoadLibrary("USER32"), "EnumDisplayDevicesA");
    45.  
    46. numMatchingDisplays = 0;
    47. if (EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&name) == 0)
    48. {
    49. printf("getDisplay - EnumDisplayMonitors failed\n");
    50. return NULL;
    51. }
    52.  
    53. if (numMatchingDisplays != 1 ) // there is a problem we should only have one
    54. {
    55. printf("getDisplay - wrong number of displays %i", numMatchingDisplays);
    56. return NULL;
    57. }
    58. else
    59. {
    60. if ((dispHand = CreateDC(name, name, NULL, NULL)) == NULL)
    61. {
    62. printf("getDisplay - CreateDC failed");
    63. return NULL;
    64. }
    65. else
    66. {
    67. return dispHand;
    68. }
    69. }
    70. }
    71.  
    72.  
    73. gamma_ramp::gamma_ramp(int Screen, int leftIn, int topIn)
    74. {
    75. screen = Screen;
    76. left = leftIn;
    77. top = topIn;
    78. clipRegion.left = left;
    79. clipRegion.top = top;
    80.  
    81. display = getDisplay();
    82. if (display == NULL)
    83. {
    84. ramp_buffer = 0;
    85. red = 0;
    86. green = 0;
    87. blue = 0;
    88. printf("gamma_ramp::gamma_ramp - error failed to get display handle");
    89. }
    90. else // set up the gamma tables
    91. }
    To copy to clipboard, switch view to plain text mode 

    On X11 I just pass in the desktop -> screenNumber since X11 uses this to allow access to the video card gamma table. For for OS/X and Windows I needed to pass in a set of coordinates that were located on the display I wanted to manipulate the gamma table for and then parse through a list of devices to find the one that contained these coordinates and then get it's handle to use internal in the gamma_ramp class.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.