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