1 /* 2 * Copyright 2003-2006, Haiku Inc. 3 * Authors: 4 * Stefano Ceccherini (burton666@libero.it). 5 * Carwyn Jones (turok2@currantbun.com) 6 * 7 * Distributed under the terms of the MIT License. 8 */ 9 10 11 #include <DirectWindow.h> 12 #include <Screen.h> 13 14 #include <clipping.h> 15 #include <AppServerLink.h> 16 #include <DirectWindowPrivate.h> 17 #include <ServerProtocol.h> 18 19 20 // We don't need this kind of locking, since the directDaemonFunc 21 // doesn't access critical shared data. 22 #define DW_NEEDS_LOCKING 0 23 24 enum dw_status_bits { 25 DW_STATUS_AREA_CLONED = 0x1, 26 DW_STATUS_THREAD_STARTED = 0x2, 27 DW_STATUS_SEM_CREATED = 0x4 28 }; 29 30 31 BDirectWindow::BDirectWindow(BRect frame, const char *title, window_type type, 32 uint32 flags, uint32 workspace) 33 : BWindow(frame, title, type, flags, workspace) 34 { 35 InitData(); 36 } 37 38 39 BDirectWindow::BDirectWindow(BRect frame, const char *title, window_look look, 40 window_feel feel, uint32 flags, uint32 workspace) 41 : BWindow(frame, title, look, feel, flags, workspace) 42 { 43 InitData(); 44 } 45 46 47 BDirectWindow::~BDirectWindow() 48 { 49 DisposeData(); 50 } 51 52 53 // start of regular BWindow API 54 BArchivable * 55 BDirectWindow::Instantiate(BMessage *data) 56 { 57 return NULL; 58 } 59 60 61 status_t 62 BDirectWindow::Archive(BMessage *data, bool deep) const 63 { 64 return inherited::Archive(data, deep); 65 } 66 67 68 void 69 BDirectWindow::Quit() 70 { 71 inherited::Quit(); 72 } 73 74 75 void 76 BDirectWindow::DispatchMessage(BMessage *message, BHandler *handler) 77 { 78 inherited::DispatchMessage(message, handler); 79 } 80 81 82 void 83 BDirectWindow::MessageReceived(BMessage *message) 84 { 85 inherited::MessageReceived(message); 86 } 87 88 89 void 90 BDirectWindow::FrameMoved(BPoint new_position) 91 { 92 inherited::FrameMoved(new_position); 93 } 94 95 96 void 97 BDirectWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws) 98 { 99 inherited::WorkspacesChanged(old_ws, new_ws); 100 } 101 102 103 void 104 BDirectWindow::WorkspaceActivated(int32 ws, bool state) 105 { 106 inherited::WorkspaceActivated(ws, state); 107 } 108 109 110 void 111 BDirectWindow::FrameResized(float new_width, float new_height) 112 { 113 inherited::FrameResized(new_width, new_height); 114 } 115 116 117 void 118 BDirectWindow::Minimize(bool minimize) 119 { 120 inherited::Minimize(minimize); 121 } 122 123 124 void 125 BDirectWindow::Zoom(BPoint rec_position, float rec_width, float rec_height) 126 { 127 inherited::Zoom(rec_position, rec_width, rec_height); 128 } 129 130 131 void 132 BDirectWindow::ScreenChanged(BRect screen_size, color_space depth) 133 { 134 inherited::ScreenChanged(screen_size, depth); 135 } 136 137 138 void 139 BDirectWindow::MenusBeginning() 140 { 141 inherited::MenusBeginning(); 142 } 143 144 145 void 146 BDirectWindow::MenusEnded() 147 { 148 inherited::MenusEnded(); 149 } 150 151 152 void 153 BDirectWindow::WindowActivated(bool state) 154 { 155 inherited::WindowActivated(state); 156 } 157 158 159 void 160 BDirectWindow::Show() 161 { 162 inherited::Show(); 163 } 164 165 166 void 167 BDirectWindow::Hide() 168 { 169 inherited::Hide(); 170 } 171 172 173 BHandler * 174 BDirectWindow::ResolveSpecifier(BMessage *msg, int32 index, 175 BMessage *specifier, int32 form, const char *property) 176 { 177 return inherited::ResolveSpecifier(msg, index, specifier, form, property); 178 } 179 180 181 status_t 182 BDirectWindow::GetSupportedSuites(BMessage *data) 183 { 184 return inherited::GetSupportedSuites(data); 185 } 186 187 188 status_t 189 BDirectWindow::Perform(perform_code d, void *arg) 190 { 191 return inherited::Perform(d, arg); 192 } 193 194 195 void 196 BDirectWindow::task_looper() 197 { 198 inherited::task_looper(); 199 } 200 201 202 BMessage * 203 BDirectWindow::ConvertToMessage(void *raw, int32 code) 204 { 205 return inherited::ConvertToMessage(raw, code); 206 } 207 208 209 // #pragma mark - BDirectWindow specific API 210 211 212 void 213 BDirectWindow::DirectConnected(direct_buffer_info *info) 214 { 215 // implemented in subclasses 216 } 217 218 219 status_t 220 BDirectWindow::GetClippingRegion(BRegion *region, BPoint *origin) const 221 { 222 if (region == NULL) 223 return B_BAD_VALUE; 224 225 if (IsLocked() || !LockDirect()) 226 return B_ERROR; 227 228 if (fInDirectConnect) { 229 UnlockDirect(); 230 return B_ERROR; 231 } 232 233 // BPoint's coordinates are floats. We can only work 234 // with integers._DaemonStarter 235 int32 originX, originY; 236 if (origin == NULL) { 237 originX = 0; 238 originY = 0; 239 } else { 240 originX = (int32)origin->x; 241 originY = (int32)origin->y; 242 } 243 244 #ifndef HAIKU_TARGET_PLATFORM_DANO 245 // Since we are friend of BRegion, we can access its private members. 246 // Otherwise, we would need to call BRegion::Include(clipping_rect) 247 // for every clipping_rect in our clip_list, and that would be much 248 // more overkill than this (tested ). 249 region->set_size(fBufferDesc->clip_list_count); 250 region->count = fBufferDesc->clip_list_count; 251 region->bound = fBufferDesc->clip_bounds; 252 for (uint32 c = 0; c < fBufferDesc->clip_list_count; c++) 253 region->data[c] = fBufferDesc->clip_list[c]; 254 255 // adjust bounds by the given origin point 256 region->OffsetBy(-originX, -originY); 257 #endif 258 259 UnlockDirect(); 260 261 return B_OK; 262 263 } 264 265 266 status_t 267 BDirectWindow::SetFullScreen(bool enable) 268 { 269 if (fIsFullScreen == enable) 270 return B_OK; 271 272 status_t status = B_ERROR; 273 if (Lock()) { 274 fLink->StartMessage(AS_DIRECT_WINDOW_SET_FULLSCREEN); 275 fLink->Attach<bool>(enable); 276 277 if (fLink->FlushWithReply(status) == B_OK 278 && status == B_OK) { 279 fIsFullScreen = enable; 280 } 281 Unlock(); 282 } 283 return status; 284 } 285 286 287 bool 288 BDirectWindow::IsFullScreen() const 289 { 290 return fIsFullScreen; 291 } 292 293 294 /*static*/ 295 bool 296 BDirectWindow::SupportsWindowMode(screen_id id) 297 { 298 /* display_mode mode; 299 status_t status = BScreen(id).GetMode(&mode); 300 if (status == B_OK) 301 return mode.flags & B_PARALLEL_ACCESS; 302 303 return false;*/ 304 // TODO: Apparently, the above is false for the vesa driver, 305 // but enabling it doesn't do any harm... maybe we should just return always true. 306 // At least, I can't see why window mode shouldn't be supported. 307 // additional NOTE: it probably depends on wether hardware cursor is supported or 308 // not 309 return true; 310 } 311 312 313 // #pragma mark - Private methods 314 315 /* static */ 316 int32 317 BDirectWindow::_DaemonStarter(void *arg) 318 { 319 return static_cast<BDirectWindow *>(arg)->DirectDaemonFunc(); 320 } 321 322 323 int32 324 BDirectWindow::DirectDaemonFunc() 325 { 326 while (!fDaemonKiller) { 327 // This sem is released by the app_server when our 328 // clipping region changes, or when our window is moved, 329 // resized, etc. etc. 330 status_t status; 331 do { 332 status = acquire_sem(fDisableSem); 333 } while (status == B_INTERRUPTED); 334 335 if (status < B_OK) 336 return -1; 337 338 if (LockDirect()) { 339 if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START) 340 fConnectionEnable = true; 341 342 fInDirectConnect = true; 343 DirectConnected(fBufferDesc); 344 fInDirectConnect = false; 345 346 if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP) 347 fConnectionEnable = false; 348 349 UnlockDirect(); 350 } 351 352 // The app_server then waits (with a timeout) on this sem. 353 // If we aren't quick enough to release this sem, our app 354 // will be terminated by the app_server 355 if (release_sem(fDisableSemAck) != B_OK) 356 return -1; 357 } 358 359 return 0; 360 } 361 362 363 // LockDirect() and UnlockDirect() are no-op on R5. I tried to call (R5's) LockDirect() 364 // repeatedly, from the same thread and from different threads, nothing happened. 365 // I implemented them anyway, as they were the first methods I wrote 366 // in this class (As you can see, I even needed to cast away their constness 367 // to make them do something useful). 368 // They're not needed though, as the direct_daemon_thread doesn't change 369 // any shared data. They are probably here for future enhancements (see also the 370 // comment in DriverSetup() 371 bool 372 BDirectWindow::LockDirect() const 373 { 374 status_t status = B_OK; 375 376 #if DW_NEEDS_LOCKING 377 BDirectWindow *casted = const_cast<BDirectWindow *>(this); 378 379 if (atomic_add(&casted->fDirectLock, 1) > 0) { 380 do { 381 status = acquire_sem(fDirectSem); 382 } while (status == B_INTERRUPTED); 383 } 384 385 if (status == B_OK) { 386 casted->fDirectLockOwner = find_thread(NULL); 387 casted->fDirectLockCount++; 388 } 389 #endif 390 391 return status == B_OK; 392 } 393 394 395 void 396 BDirectWindow::UnlockDirect() const 397 { 398 #if DW_NEEDS_LOCKING 399 BDirectWindow *casted = const_cast<BDirectWindow *>(this); 400 401 if (atomic_add(&casted->fDirectLock, -1) > 1) 402 release_sem(casted->fDirectSem); 403 404 casted->fDirectLockCount--; 405 #endif 406 } 407 408 409 void 410 BDirectWindow::InitData() 411 { 412 fConnectionEnable = false; 413 fIsFullScreen = false; 414 fInDirectConnect = false; 415 416 fInitStatus = 0; 417 418 fDirectDriverReady = false; 419 fDirectDriverType = 0; 420 fDirectDriverToken = 0; 421 direct_driver = NULL; 422 423 status_t status = B_ERROR; 424 struct direct_window_sync_data syncData; 425 if (Lock()) { 426 fLink->StartMessage(AS_DIRECT_WINDOW_GET_SYNC_DATA); 427 if (fLink->FlushWithReply(status) == B_OK 428 && status == B_OK) { 429 fLink->Read<direct_window_sync_data>(&syncData); 430 } 431 Unlock(); 432 } 433 if (status < B_OK) 434 return; 435 436 #if DW_NEEDS_LOCKING 437 fDirectLock = 0; 438 fDirectLockCount = 0; 439 fDirectLockOwner = -1; 440 fDirectLockStack = NULL; 441 fDirectSem = create_sem(1, "direct sem"); 442 if (fDirectSem > 0) 443 fInitStatus |= DW_STATUS_SEM_CREATED; 444 #endif 445 446 fSourceClippingArea = syncData.area; 447 fDisableSem = syncData.disable_sem; 448 fDisableSemAck = syncData.disable_sem_ack; 449 450 fClonedClippingArea = clone_area("Clone direct area", (void**)&fBufferDesc, 451 B_ANY_ADDRESS, B_READ_AREA, fSourceClippingArea); 452 453 if (fClonedClippingArea > 0) { 454 fInitStatus |= DW_STATUS_AREA_CLONED; 455 456 fDirectDaemonId = spawn_thread(_DaemonStarter, "direct daemon", 457 B_DISPLAY_PRIORITY, this); 458 459 if (fDirectDaemonId > 0) { 460 fDaemonKiller = false; 461 if (resume_thread(fDirectDaemonId) == B_OK) 462 fInitStatus |= DW_STATUS_THREAD_STARTED; 463 else 464 kill_thread(fDirectDaemonId); 465 } 466 } 467 } 468 469 470 void 471 BDirectWindow::DisposeData() 472 { 473 // wait until the connection terminates: we can't destroy 474 // the object until the client receives the B_DIRECT_STOP 475 // notification, or bad things will happen 476 while (fConnectionEnable) 477 snooze(50000); 478 479 LockDirect(); 480 481 if (fInitStatus & DW_STATUS_THREAD_STARTED) { 482 fDaemonKiller = true; 483 // Release this sem, otherwise the Direct daemon thread 484 // will wait forever on it 485 release_sem(fDisableSem); 486 status_t retVal; 487 wait_for_thread(fDirectDaemonId, &retVal); 488 } 489 490 #if DW_NEEDS_LOCKING 491 if (fInitStatus & DW_STATUS_SEM_CREATED) 492 delete_sem(fDirectSem); 493 #endif 494 495 if (fInitStatus & DW_STATUS_AREA_CLONED) 496 delete_area(fClonedClippingArea); 497 } 498 499 500 status_t 501 BDirectWindow::DriverSetup() const 502 { 503 // Unimplemented in R5. 504 // This function is probably here because they wanted, in a future time, 505 // to implement graphic acceleration within BDirectWindow 506 // (in fact, there is also a BDirectDriver member in BDirectWindow, 507 // though it's not used). 508 509 return B_OK; 510 } 511 512 513 void BDirectWindow::_ReservedDirectWindow1() {} 514 void BDirectWindow::_ReservedDirectWindow2() {} 515 void BDirectWindow::_ReservedDirectWindow3() {} 516 void BDirectWindow::_ReservedDirectWindow4() {} 517