1 /* 2 * Copyright 2005-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 /** Manages all available physical screens */ 10 11 12 #include "ScreenManager.h" 13 14 #include "Screen.h" 15 #include "ServerConfig.h" 16 17 #include "RemoteHWInterface.h" 18 19 #include <Autolock.h> 20 #include <Entry.h> 21 #include <NodeMonitor.h> 22 23 #include <new> 24 25 using std::nothrow; 26 27 28 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 29 # include "AccelerantHWInterface.h" 30 #else 31 # include "ViewHWInterface.h" 32 # include "DWindowHWInterface.h" 33 #endif 34 35 36 ScreenManager* gScreenManager; 37 38 39 class ScreenChangeListener : public HWInterfaceListener { 40 public: 41 ScreenChangeListener(ScreenManager& manager, 42 Screen* screen); 43 44 private: 45 virtual void ScreenChanged(HWInterface* interface); 46 47 ScreenManager& fManager; 48 Screen* fScreen; 49 }; 50 51 52 ScreenChangeListener::ScreenChangeListener(ScreenManager& manager, 53 Screen* screen) 54 : 55 fManager(manager), 56 fScreen(screen) 57 { 58 } 59 60 61 void 62 ScreenChangeListener::ScreenChanged(HWInterface* interface) 63 { 64 fManager.ScreenChanged(fScreen); 65 } 66 67 68 ScreenManager::ScreenManager() 69 : 70 BLooper("screen manager"), 71 fScreenList(4) 72 { 73 _ScanDrivers(); 74 75 // turn on node monitoring the graphics driver directory 76 BEntry entry("/dev/graphics"); 77 node_ref nodeRef; 78 if (entry.InitCheck() == B_OK && entry.GetNodeRef(&nodeRef) == B_OK) 79 watch_node(&nodeRef, B_WATCH_DIRECTORY, this); 80 } 81 82 83 ScreenManager::~ScreenManager() 84 { 85 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 86 screen_item* item = fScreenList.ItemAt(i); 87 88 delete item->screen; 89 delete item->listener; 90 delete item; 91 } 92 } 93 94 95 Screen* 96 ScreenManager::ScreenAt(int32 index) const 97 { 98 if (!IsLocked()) 99 debugger("Called ScreenManager::ScreenAt() without lock!"); 100 101 screen_item* item = fScreenList.ItemAt(index); 102 if (item != NULL) 103 return item->screen; 104 105 return NULL; 106 } 107 108 109 int32 110 ScreenManager::CountScreens() const 111 { 112 if (!IsLocked()) 113 debugger("Called ScreenManager::CountScreens() without lock!"); 114 115 return fScreenList.CountItems(); 116 } 117 118 119 status_t 120 ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList, 121 int32 wishCount, const char* target, bool force, ScreenList& list) 122 { 123 BAutolock locker(this); 124 int32 added = 0; 125 126 // TODO: don't ignore the wish list 127 128 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 129 screen_item* item = fScreenList.ItemAt(i); 130 131 if (item->owner == NULL && list.AddItem(item->screen)) { 132 item->owner = owner; 133 added++; 134 } 135 } 136 137 if (added == 0 && target != NULL) { 138 // there's a specific target screen we want to initialize 139 // TODO: right now we only support remote screens, but we could 140 // also target specific accelerants to support other graphics cards 141 HWInterface* interface; 142 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST 143 interface = new(nothrow) ViewHWInterface(); 144 #else 145 interface = new(nothrow) RemoteHWInterface(target); 146 #endif 147 if (interface != NULL) { 148 screen_item* item = _AddHWInterface(interface); 149 if (item != NULL && list.AddItem(item->screen)) { 150 item->owner = owner; 151 added++; 152 } 153 } 154 } 155 156 return added > 0 ? B_OK : B_ENTRY_NOT_FOUND; 157 } 158 159 160 void 161 ScreenManager::ReleaseScreens(ScreenList& list) 162 { 163 BAutolock locker(this); 164 165 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 166 screen_item* item = fScreenList.ItemAt(i); 167 168 for (int32 j = 0; j < list.CountItems(); j++) { 169 Screen* screen = list.ItemAt(j); 170 171 if (item->screen == screen) 172 item->owner = NULL; 173 } 174 } 175 } 176 177 178 void 179 ScreenManager::ScreenChanged(Screen* screen) 180 { 181 BAutolock locker(this); 182 183 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 184 screen_item* item = fScreenList.ItemAt(i); 185 if (item->screen == screen) 186 item->owner->ScreenChanged(screen); 187 } 188 } 189 190 191 void 192 ScreenManager::_ScanDrivers() 193 { 194 HWInterface* interface = NULL; 195 196 // Eventually we will loop through drivers until 197 // one can't initialize in order to support multiple monitors. 198 // For now, we'll just load one and be done with it. 199 200 // ToDo: to make monitoring the driver directory useful, we need more 201 // power and data here, and should do the scanning on our own 202 203 bool initDrivers = true; 204 while (initDrivers) { 205 206 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 207 interface = new AccelerantHWInterface(); 208 #elif defined(USE_DIRECT_WINDOW_TEST_MODE) 209 interface = new DWindowHWInterface(); 210 #else 211 interface = new ViewHWInterface(); 212 #endif 213 214 _AddHWInterface(interface); 215 initDrivers = false; 216 } 217 } 218 219 220 ScreenManager::screen_item* 221 ScreenManager::_AddHWInterface(HWInterface* interface) 222 { 223 Screen* screen = new(nothrow) Screen(interface, fScreenList.CountItems()); 224 if (screen == NULL) { 225 delete interface; 226 return NULL; 227 } 228 229 // The interface is now owned by the screen 230 231 if (screen->Initialize() >= B_OK) { 232 screen_item* item = new(nothrow) screen_item; 233 234 if (item != NULL) { 235 item->screen = screen; 236 item->owner = NULL; 237 item->listener = new(nothrow) ScreenChangeListener(*this, screen); 238 if (item->listener != NULL 239 && interface->AddListener(item->listener)) { 240 if (fScreenList.AddItem(item)) 241 return item; 242 243 interface->RemoveListener(item->listener); 244 } 245 246 delete item->listener; 247 delete item; 248 } 249 } 250 251 delete screen; 252 return NULL; 253 } 254 255 256 void 257 ScreenManager::MessageReceived(BMessage* message) 258 { 259 switch (message->what) { 260 case B_NODE_MONITOR: 261 // TODO: handle notification 262 break; 263 264 default: 265 BHandler::MessageReceived(message); 266 } 267 } 268 269