1 /* 2 * Copyright 2003-2005, 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 Unlock(); 281 } 282 return status; 283 } 284 285 286 bool 287 BDirectWindow::IsFullScreen() const 288 { 289 return fIsFullScreen; 290 } 291 292 293 /*static*/ 294 bool 295 BDirectWindow::SupportsWindowMode(screen_id id) 296 { 297 /* display_mode mode; 298 status_t status = BScreen(id).GetMode(&mode); 299 if (status == B_OK) 300 return mode.flags & B_PARALLEL_ACCESS; 301 302 return false;*/ 303 // TODO: Apparently, the above is false for the vesa driver, 304 // but enabling it doesn't do any harm... maybe we should just return always true. 305 // At least, I can't see why window mode shouldn't be supported. 306 return true; 307 } 308 309 310 // #pragma mark - Private methods 311 312 /* static */ 313 int32 314 BDirectWindow::_DaemonStarter(void *arg) 315 { 316 return static_cast<BDirectWindow *>(arg)->DirectDaemonFunc(); 317 } 318 319 320 int32 321 BDirectWindow::DirectDaemonFunc() 322 { 323 while (!fDaemonKiller) { 324 // This sem is released by the app_server when our 325 // clipping region changes, or when our window is moved, 326 // resized, etc. etc. 327 status_t status; 328 do { 329 status = acquire_sem(fDisableSem); 330 } while (status == B_INTERRUPTED); 331 332 if (status < B_OK) 333 return -1; 334 335 if (LockDirect()) { 336 if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START) 337 fConnectionEnable = true; 338 339 fInDirectConnect = true; 340 DirectConnected(fBufferDesc); 341 fInDirectConnect = false; 342 343 if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP) 344 fConnectionEnable = false; 345 346 UnlockDirect(); 347 } 348 349 // The app_server then waits (with a timeout) on this sem. 350 // If we aren't quick enough to release this sem, our app 351 // will be terminated by the app_server 352 if (release_sem(fDisableSemAck) != B_OK) 353 return -1; 354 } 355 356 return 0; 357 } 358 359 360 // LockDirect() and UnlockDirect() are no-op on R5. I tried to call (R5's) LockDirect() 361 // repeatedly, from the same thread and from different threads, nothing happened. 362 // I implemented them anyway, as they were the first methods I wrote 363 // in this class (As you can see, I even needed to cast away their constness 364 // to make them do something useful). 365 // They're not needed though, as the direct_daemon_thread doesn't change 366 // any shared data. They are probably here for future enhancements (see also the 367 // comment in DriverSetup() 368 bool 369 BDirectWindow::LockDirect() const 370 { 371 status_t status = B_OK; 372 373 #if DW_NEEDS_LOCKING 374 BDirectWindow *casted = const_cast<BDirectWindow *>(this); 375 376 if (atomic_add(&casted->fDirectLock, 1) > 0) { 377 do { 378 status = acquire_sem(fDirectSem); 379 } while (status == B_INTERRUPTED); 380 } 381 382 if (status == B_OK) { 383 casted->fDirectLockOwner = find_thread(NULL); 384 casted->fDirectLockCount++; 385 } 386 #endif 387 388 return status == B_OK; 389 } 390 391 392 void 393 BDirectWindow::UnlockDirect() const 394 { 395 #if DW_NEEDS_LOCKING 396 BDirectWindow *casted = const_cast<BDirectWindow *>(this); 397 398 if (atomic_add(&casted->fDirectLock, -1) > 1) 399 release_sem(casted->fDirectSem); 400 401 casted->fDirectLockCount--; 402 #endif 403 } 404 405 406 void 407 BDirectWindow::InitData() 408 { 409 fConnectionEnable = false; 410 fIsFullScreen = false; 411 fInDirectConnect = false; 412 413 fInitStatus = 0; 414 415 fDirectDriverReady = false; 416 fDirectDriverType = 0; 417 fDirectDriverToken = 0; 418 direct_driver = NULL; 419 420 status_t status = B_ERROR; 421 struct direct_window_sync_data syncData; 422 if (Lock()) { 423 fLink->StartMessage(AS_DIRECT_WINDOW_GET_SYNC_DATA); 424 if (fLink->FlushWithReply(status) == B_OK 425 && status == B_OK) { 426 fLink->Read<direct_window_sync_data>(&syncData); 427 } 428 Unlock(); 429 } 430 if (status < B_OK) 431 return; 432 433 #if DW_NEEDS_LOCKING 434 fDirectLock = 0; 435 fDirectLockCount = 0; 436 fDirectLockOwner = -1; 437 fDirectLockStack = NULL; 438 fDirectSem = create_sem(1, "direct sem"); 439 if (fDirectSem > 0) 440 fInitStatus |= DW_STATUS_SEM_CREATED; 441 #endif 442 443 fSourceClippingArea = syncData.area; 444 fDisableSem = syncData.disable_sem; 445 fDisableSemAck = syncData.disable_sem_ack; 446 447 fClonedClippingArea = clone_area("Clone direct area", (void**)&fBufferDesc, 448 B_ANY_ADDRESS, B_READ_AREA, fSourceClippingArea); 449 450 if (fSourceClippingArea > 0) { 451 fInitStatus |= DW_STATUS_AREA_CLONED; 452 453 fDirectDaemonId = spawn_thread(_DaemonStarter, "direct daemon", 454 B_DISPLAY_PRIORITY, this); 455 456 if (fDirectDaemonId > 0) { 457 fDaemonKiller = false; 458 if (resume_thread(fDirectDaemonId) == B_OK) 459 fInitStatus |= DW_STATUS_THREAD_STARTED; 460 else 461 kill_thread(fDirectDaemonId); 462 } 463 } 464 } 465 466 467 void 468 BDirectWindow::DisposeData() 469 { 470 // wait until the connection terminates: we can't destroy 471 // the object until the client receives the B_DIRECT_STOP 472 // notification, or bad things will happen 473 while (fConnectionEnable) 474 snooze(50000); 475 476 LockDirect(); 477 478 if (fInitStatus & DW_STATUS_THREAD_STARTED) { 479 fDaemonKiller = true; 480 // Release this sem, otherwise the Direct daemon thread 481 // will wait forever on it 482 release_sem(fDisableSem); 483 status_t retVal; 484 wait_for_thread(fDirectDaemonId, &retVal); 485 } 486 487 #if DW_NEEDS_LOCKING 488 if (fInitStatus & DW_STATUS_SEM_CREATED) 489 delete_sem(fDirectSem); 490 #endif 491 492 if (fInitStatus & DW_STATUS_AREA_CLONED) 493 delete_area(fClonedClippingArea); 494 } 495 496 497 status_t 498 BDirectWindow::DriverSetup() const 499 { 500 // Unimplemented in R5. 501 // This function is probably here because they wanted, in a future time, 502 // to implement graphic acceleration within BDirectWindow 503 // (in fact, there is also a BDirectDriver member in BDirectWindow, 504 // though it's not used). 505 506 return B_OK; 507 } 508 509 510 void BDirectWindow::_ReservedDirectWindow1() {} 511 void BDirectWindow::_ReservedDirectWindow2() {} 512 void BDirectWindow::_ReservedDirectWindow3() {} 513 void BDirectWindow::_ReservedDirectWindow4() {} 514