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, true) 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 } 86 87 88 Screen* 89 ScreenManager::ScreenAt(int32 index) const 90 { 91 if (!IsLocked()) 92 debugger("Called ScreenManager::ScreenAt() without lock!"); 93 94 screen_item* item = fScreenList.ItemAt(index); 95 if (item != NULL) 96 return item->screen.Get(); 97 98 return NULL; 99 } 100 101 102 int32 103 ScreenManager::CountScreens() const 104 { 105 if (!IsLocked()) 106 debugger("Called ScreenManager::CountScreens() without lock!"); 107 108 return fScreenList.CountItems(); 109 } 110 111 112 status_t 113 ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList, 114 int32 wishCount, const char* target, bool force, ScreenList& list) 115 { 116 BAutolock locker(this); 117 int32 added = 0; 118 119 // TODO: don't ignore the wish list 120 121 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 122 screen_item* item = fScreenList.ItemAt(i); 123 124 if (item->owner == NULL && list.AddItem(item->screen.Get())) { 125 item->owner = owner; 126 added++; 127 } 128 } 129 130 if (added == 0 && target != NULL) { 131 // there's a specific target screen we want to initialize 132 // TODO: right now we only support remote screens, but we could 133 // also target specific accelerants to support other graphics cards 134 HWInterface* interface; 135 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST 136 interface = new(nothrow) ViewHWInterface(); 137 #else 138 interface = new(nothrow) RemoteHWInterface(target); 139 #endif 140 if (interface != NULL) { 141 screen_item* item = _AddHWInterface(interface); 142 if (item != NULL && list.AddItem(item->screen.Get())) { 143 item->owner = owner; 144 added++; 145 } 146 } 147 } 148 149 return added > 0 ? B_OK : B_ENTRY_NOT_FOUND; 150 } 151 152 153 void 154 ScreenManager::ReleaseScreens(ScreenList& list) 155 { 156 BAutolock locker(this); 157 158 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 159 screen_item* item = fScreenList.ItemAt(i); 160 161 for (int32 j = 0; j < list.CountItems(); j++) { 162 Screen* screen = list.ItemAt(j); 163 164 if (item->screen.Get() == screen) 165 item->owner = NULL; 166 } 167 } 168 } 169 170 171 void 172 ScreenManager::ScreenChanged(Screen* screen) 173 { 174 BAutolock locker(this); 175 176 for (int32 i = 0; i < fScreenList.CountItems(); i++) { 177 screen_item* item = fScreenList.ItemAt(i); 178 if (item->screen.Get() == screen) 179 item->owner->ScreenChanged(screen); 180 } 181 } 182 183 184 void 185 ScreenManager::_ScanDrivers() 186 { 187 HWInterface* interface = NULL; 188 189 // Eventually we will loop through drivers until 190 // one can't initialize in order to support multiple monitors. 191 // For now, we'll just load one and be done with it. 192 193 // ToDo: to make monitoring the driver directory useful, we need more 194 // power and data here, and should do the scanning on our own 195 196 bool initDrivers = true; 197 while (initDrivers) { 198 199 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 200 interface = new AccelerantHWInterface(); 201 #elif defined(USE_DIRECT_WINDOW_TEST_MODE) 202 interface = new DWindowHWInterface(); 203 #else 204 interface = new ViewHWInterface(); 205 #endif 206 207 _AddHWInterface(interface); 208 initDrivers = false; 209 } 210 } 211 212 213 ScreenManager::screen_item* 214 ScreenManager::_AddHWInterface(HWInterface* interface) 215 { 216 ObjectDeleter<Screen> screen( 217 new(nothrow) Screen(interface, fScreenList.CountItems())); 218 if (!screen.IsSet()) { 219 delete interface; 220 return NULL; 221 } 222 223 // The interface is now owned by the screen 224 225 if (screen->Initialize() >= B_OK) { 226 screen_item* item = new(nothrow) screen_item; 227 228 if (item != NULL) { 229 item->screen.SetTo(screen.Detach()); 230 item->owner = NULL; 231 item->listener.SetTo( 232 new(nothrow) ScreenChangeListener(*this, item->screen.Get())); 233 if (item->listener.IsSet() 234 && interface->AddListener(item->listener.Get())) { 235 if (fScreenList.AddItem(item)) 236 return item; 237 238 interface->RemoveListener(item->listener.Get()); 239 } 240 241 delete item; 242 } 243 } 244 245 return NULL; 246 } 247 248 249 void 250 ScreenManager::MessageReceived(BMessage* message) 251 { 252 switch (message->what) { 253 case B_NODE_MONITOR: 254 // TODO: handle notification 255 break; 256 257 default: 258 BHandler::MessageReceived(message); 259 } 260 } 261