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 TEST_MODE == 0 138 if (added == 0 && target != NULL) { 139 // there's a specific target screen we want to initialize 140 // TODO: right now we only support remote screens, but we could 141 // also target specific accelerants to support other graphics cards 142 HWInterface* interface; 143 /*if (strncmp(target, "vnc:", 4) == 0) 144 interface = new(nothrow) VNCHWInterface(target); 145 else*/ 146 interface = new(nothrow) RemoteHWInterface(target); 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 #endif // TEST_MODE == 0 156 157 return added > 0 ? B_OK : B_ENTRY_NOT_FOUND; 158 } 159 160 161 void 162 ScreenManager::ReleaseScreens(ScreenList& list) 163 { 164 BAutolock locker(this); 165 166 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 167 screen_item* item = fScreenList.ItemAt(i); 168 169 for (int32 j = 0; j < list.CountItems(); j++) { 170 Screen* screen = list.ItemAt(j); 171 172 if (item->screen == screen) 173 item->owner = NULL; 174 } 175 } 176 } 177 178 179 void 180 ScreenManager::ScreenChanged(Screen* screen) 181 { 182 BAutolock locker(this); 183 184 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 185 screen_item* item = fScreenList.ItemAt(i); 186 if (item->screen == screen) 187 item->owner->ScreenChanged(screen); 188 } 189 } 190 191 192 void 193 ScreenManager::_ScanDrivers() 194 { 195 HWInterface* interface = NULL; 196 197 // Eventually we will loop through drivers until 198 // one can't initialize in order to support multiple monitors. 199 // For now, we'll just load one and be done with it. 200 201 // ToDo: to make monitoring the driver directory useful, we need more 202 // power and data here, and should do the scanning on our own 203 204 bool initDrivers = true; 205 while (initDrivers) { 206 207 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 208 interface = new AccelerantHWInterface(); 209 #elif defined(USE_DIRECT_WINDOW_TEST_MODE) 210 interface = new DWindowHWInterface(); 211 #else 212 interface = new ViewHWInterface(); 213 #endif 214 215 _AddHWInterface(interface); 216 initDrivers = false; 217 } 218 } 219 220 221 ScreenManager::screen_item* 222 ScreenManager::_AddHWInterface(HWInterface* interface) 223 { 224 Screen* screen = new(nothrow) Screen(interface, fScreenList.CountItems()); 225 if (screen == NULL) { 226 delete interface; 227 return NULL; 228 } 229 230 // The interface is now owned by the screen 231 232 if (screen->Initialize() >= B_OK) { 233 screen_item* item = new(nothrow) screen_item; 234 235 if (item != NULL) { 236 item->screen = screen; 237 item->owner = NULL; 238 item->listener = new(nothrow) ScreenChangeListener(*this, screen); 239 if (item->listener != NULL 240 && interface->AddListener(item->listener)) { 241 if (fScreenList.AddItem(item)) 242 return item; 243 244 interface->RemoveListener(item->listener); 245 } 246 247 delete item->listener; 248 delete item; 249 } 250 } 251 252 delete screen; 253 return NULL; 254 } 255 256 257 void 258 ScreenManager::MessageReceived(BMessage* message) 259 { 260 switch (message->what) { 261 case B_NODE_MONITOR: 262 // TODO: handle notification 263 break; 264 265 default: 266 BHandler::MessageReceived(message); 267 } 268 } 269 270