1 // license:BSD-3-Clause 2 // copyright-holders: R. Belmont 3 //============================================================ 4 // 5 // monitor_mac.cpp - Mac monitor info provider 6 // 7 // Mac OSD by R. Belmont 8 // 9 //============================================================ 10 11 #include "emu.h" 12 #include "modules/osdmodule.h" 13 #include "monitor_module.h" 14 15 #if defined(OSD_MAC) 16 17 #include <CoreFoundation/CoreFoundation.h> 18 #include <CoreGraphics/CoreGraphics.h> 19 20 #include <algorithm> 21 22 #include "modules/osdwindow.h" 23 #include "monitor_common.h" 24 #include "window.h" 25 26 //============================================================ 27 // mac_monitor_info 28 //============================================================ 29 30 class mac_monitor_info : public osd_monitor_info 31 { 32 public: mac_monitor_info(monitor_module & module,CGDirectDisplayID handle,const char * monitor_device,float aspect)33 mac_monitor_info(monitor_module &module, CGDirectDisplayID handle, const char *monitor_device, float aspect) 34 : osd_monitor_info(module, handle, monitor_device, aspect) 35 { 36 mac_monitor_info::refresh(); 37 } 38 39 private: refresh()40 void refresh() override 41 { 42 CGRect dimensions; 43 dimensions = CGDisplayBounds((CGDirectDisplayID)oshandle()); 44 45 m_pos_size = osd_rect(dimensions.origin.x, dimensions.origin.y, dimensions.size.width, dimensions.size.height); 46 m_usuable_pos_size = osd_rect(dimensions.origin.x, dimensions.origin.y, dimensions.size.width, dimensions.size.height); 47 m_is_primary = CGDisplayIsMain((CGDirectDisplayID)oshandle()); 48 } 49 }; 50 51 //============================================================ 52 // mac_monitor_module 53 //============================================================ 54 55 class mac_monitor_module : public monitor_module_base 56 { 57 public: mac_monitor_module()58 mac_monitor_module() 59 : monitor_module_base(OSD_MONITOR_PROVIDER, "sdl") 60 { 61 } 62 63 // 64 // Given a proposed rect, returns the monitor whose bounds intersect the most with it 65 // monitor_from_rect(const osd_rect & proposed)66 std::shared_ptr<osd_monitor_info> monitor_from_rect(const osd_rect& proposed) override 67 { 68 if (!m_initialized) 69 return nullptr; 70 71 // Determines whether the first intersects less with the proposed rect than the second 72 auto intersects_less = [&proposed](std::shared_ptr<osd_monitor_info> mon1, std::shared_ptr<osd_monitor_info> mon2) 73 { 74 int value1 = compute_intersection(mon1->usuable_position_size(), proposed); 75 int value2 = compute_intersection(mon2->usuable_position_size(), proposed); 76 77 return value1 < value2; 78 }; 79 80 // Find the one that intersects with the proposed rect the most 81 auto monitor = std::max_element(std::begin(list()), std::end(list()), intersects_less); 82 return *monitor; 83 } 84 monitor_from_window(const osd_window & window)85 std::shared_ptr<osd_monitor_info> monitor_from_window(const osd_window& window) override 86 { 87 // if (!m_initialized) 88 return nullptr; 89 90 // std::uint64_t display = SDL_GetWindowDisplayIndex(static_cast<const mac_window_info &>(window).platform_window()); 91 // return monitor_from_handle(display); 92 } 93 94 protected: init_internal(const osd_options & options)95 int init_internal(const osd_options& options) override 96 { 97 // make a list of monitors 98 { 99 uint32_t uNumDisplays; 100 CGDirectDisplayID *displayList; 101 102 osd_printf_verbose("Enter init_monitors\n"); 103 104 // pass NULL to get the number of displays 105 CGGetActiveDisplayList(1, NULL, &uNumDisplays); 106 107 displayList = (CGDirectDisplayID *)malloc(sizeof(CGDirectDisplayID) * uNumDisplays); 108 CGGetActiveDisplayList(uNumDisplays, displayList, &uNumDisplays); 109 110 for (uint32_t disp = 0; disp < uNumDisplays; disp++) 111 { 112 char temp[64]; 113 snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, disp); 114 115 // allocate a new monitor info 116 std::shared_ptr<osd_monitor_info> monitor = std::make_shared<mac_monitor_info>(*this, displayList[disp], temp, 1.0f); 117 118 osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename(), 119 monitor->position_size().width(), monitor->position_size().height()); 120 121 // guess the aspect ratio assuming square pixels 122 monitor->set_aspect(static_cast<float>(monitor->position_size().width()) / static_cast<float>(monitor->position_size().height())); 123 124 // hook us into the list 125 add_monitor(monitor); 126 } 127 128 free(displayList); 129 } 130 osd_printf_verbose("Leave init_monitors\n"); 131 132 return 0; 133 } 134 compute_intersection(const osd_rect & rect1,const osd_rect & rect2)135 static int compute_intersection(const osd_rect &rect1, const osd_rect &rect2) 136 { 137 int min0, min1, max0, max1, result = 0; 138 139 // if either rect is empty, bail early (shouldn't happen, but...) 140 if (rect1.width() + rect1.height() == 0) 141 { 142 return 0; 143 } 144 if (rect2.width() + rect2.height() == 0) 145 { 146 return 0; 147 } 148 149 // do the X intersection 150 min0 = rect1.left(); 151 max0 = min0 + rect1.width(); 152 min1 = rect2.left(); 153 max1 = min1 + rect2.width(); 154 if (min1 > min0) 155 { 156 min0 = min1; 157 } 158 if (max1 > max0) 159 { 160 max0 = max1; 161 } 162 result = max0 - min0; 163 164 // and now the Y intersection 165 min0 = rect1.top(); 166 max0 = min0 + rect1.height(); 167 min1 = rect2.top(); 168 max1 = min1 + rect2.height(); 169 if (min1 > min0) 170 { 171 min0 = min1; 172 } 173 if (max1 > max0) 174 { 175 max0 = max1; 176 } 177 result += max0 - min0; 178 179 return result; 180 } 181 182 private: 183 }; 184 185 #else 186 MODULE_NOT_SUPPORTED(mac_monitor_module, OSD_MONITOR_PROVIDER, "sdl") 187 #endif 188 189 MODULE_DEFINITION(MONITOR_MAC, mac_monitor_module) 190