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 #ifdef COMPILE_FOR_R5 11 #include "/boot/develop/headers/be/interface/Window.h" 12 #endif 13 14 #include <DirectWindow.h> 15 #include <clipping.h> 16 17 #ifdef COMPILE_FOR_R5 18 #include <R5_AppServerLink.h> 19 #include <R5_Session.h> 20 #define DW_GET_SYNC_DATA 0x880 21 #define DW_SET_FULLSCREEN 0x881 22 #define DW_SUPPORTS_WINDOW_MODE 0xF2C 23 #endif 24 25 // Compiling for DANO/Zeta is broken as it doesn't have BRegion::set_size() 26 #ifdef COMPILE_FOR_DANO 27 #warning "##### Building BDirectWindow for TARGET_PLATFORM=dano (DANO/Zeta) is broken #####" 28 #endif 29 30 #ifdef __HAIKU__ 31 #include <AppServerLink.h> 32 #include <ServerProtocol.h> 33 #endif 34 35 // TODO: We'll want to move this to a private header, 36 // accessible by the app server. 37 struct dw_sync_data 38 { 39 area_id area; 40 sem_id disableSem; 41 sem_id disableSemAck; 42 }; 43 44 45 // We don't need this kind of locking, since the directDeamonFunc 46 // doesn't access critical shared data. 47 #define DW_NEEDS_LOCKING 0 48 49 enum dw_status_bits { 50 DW_STATUS_AREA_CLONED = 0x1, 51 DW_STATUS_THREAD_STARTED = 0x2, 52 DW_STATUS_SEM_CREATED = 0x4 53 }; 54 55 56 BDirectWindow::BDirectWindow(BRect frame, const char *title, window_type type, uint32 flags, uint32 workspace) 57 :BWindow(frame, title, type, flags, workspace) 58 { 59 InitData(); 60 } 61 62 63 BDirectWindow::BDirectWindow(BRect frame, const char *title, window_look look, window_feel feel, uint32 flags, uint32 workspace) 64 :BWindow(frame, title, look, feel, flags, workspace) 65 { 66 InitData(); 67 } 68 69 70 BDirectWindow::~BDirectWindow() 71 { 72 DisposeData(); 73 } 74 75 76 // start of regular BWindow API 77 BArchivable * 78 BDirectWindow::Instantiate(BMessage *data) 79 { 80 return NULL; 81 } 82 83 84 status_t 85 BDirectWindow::Archive(BMessage *data, bool deep) const 86 { 87 return inherited::Archive(data, deep); 88 } 89 90 91 void 92 BDirectWindow::Quit() 93 { 94 inherited::Quit(); 95 } 96 97 98 void 99 BDirectWindow::DispatchMessage(BMessage *message, BHandler *handler) 100 { 101 inherited::DispatchMessage(message, handler); 102 } 103 104 105 void 106 BDirectWindow::MessageReceived(BMessage *message) 107 { 108 inherited::MessageReceived(message); 109 } 110 111 112 void 113 BDirectWindow::FrameMoved(BPoint new_position) 114 { 115 inherited::FrameMoved(new_position); 116 } 117 118 119 void 120 BDirectWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws) 121 { 122 inherited::WorkspacesChanged(old_ws, new_ws); 123 } 124 125 126 void 127 BDirectWindow::WorkspaceActivated(int32 ws, bool state) 128 { 129 inherited::WorkspaceActivated(ws, state); 130 } 131 132 133 void 134 BDirectWindow::FrameResized(float new_width, float new_height) 135 { 136 inherited::FrameResized(new_width, new_height); 137 } 138 139 140 void 141 BDirectWindow::Minimize(bool minimize) 142 { 143 inherited::Minimize(minimize); 144 } 145 146 147 void 148 BDirectWindow::Zoom(BPoint rec_position, float rec_width, float rec_height) 149 { 150 inherited::Zoom(rec_position, rec_width, rec_height); 151 } 152 153 154 void 155 BDirectWindow::ScreenChanged(BRect screen_size, color_space depth) 156 { 157 inherited::ScreenChanged(screen_size, depth); 158 } 159 160 161 void 162 BDirectWindow::MenusBeginning() 163 { 164 inherited::MenusBeginning(); 165 } 166 167 168 void 169 BDirectWindow::MenusEnded() 170 { 171 inherited::MenusEnded(); 172 } 173 174 175 void 176 BDirectWindow::WindowActivated(bool state) 177 { 178 inherited::WindowActivated(state); 179 } 180 181 182 void 183 BDirectWindow::Show() 184 { 185 inherited::Show(); 186 } 187 188 189 void 190 BDirectWindow::Hide() 191 { 192 inherited::Hide(); 193 } 194 195 196 BHandler * 197 BDirectWindow::ResolveSpecifier(BMessage *msg, int32 index, 198 BMessage *specifier, int32 form, const char *property) 199 { 200 return inherited::ResolveSpecifier(msg, index, specifier, form, property); 201 } 202 203 204 status_t 205 BDirectWindow::GetSupportedSuites(BMessage *data) 206 { 207 return inherited::GetSupportedSuites(data); 208 } 209 210 211 status_t 212 BDirectWindow::Perform(perform_code d, void *arg) 213 { 214 return inherited::Perform(d, arg); 215 } 216 217 218 void 219 BDirectWindow::task_looper() 220 { 221 inherited::task_looper(); 222 } 223 224 225 BMessage * 226 BDirectWindow::ConvertToMessage(void *raw, int32 code) 227 { 228 return inherited::ConvertToMessage(raw, code); 229 } 230 // end of BWindow API 231 232 233 // BDirectWindow specific API 234 void 235 BDirectWindow::DirectConnected(direct_buffer_info *info) 236 { 237 //implemented in subclasses 238 } 239 240 241 status_t 242 BDirectWindow::GetClippingRegion(BRegion *region, BPoint *origin) const 243 { 244 if (region == NULL) 245 return B_BAD_VALUE; 246 247 if (IsLocked()) 248 return B_ERROR; 249 250 if (!LockDirect()) 251 return B_ERROR; 252 253 if (in_direct_connect) { 254 UnlockDirect(); 255 return B_ERROR; 256 } 257 258 // BPoint's coordinates are floats. We can only work 259 // with integers. 260 int32 originX, originY; 261 if (origin == NULL) { 262 originX = 0; 263 originY = 0; 264 } else { 265 originX = (int32)origin->x; 266 originY = (int32)origin->y; 267 } 268 269 #ifndef COMPILE_FOR_DANO 270 // Since we are friend of BRegion, we can access its private members. 271 // Otherwise, we would need to call BRegion::Include(clipping_rect) 272 // for every clipping_rect in our clip_list, and that would be much 273 // more overkill than this (tested ). 274 region->set_size(buffer_desc->clip_list_count); 275 region->count = buffer_desc->clip_list_count; 276 region->bound = buffer_desc->clip_bounds; 277 278 // adjust bounds by the given origin point 279 offset_rect(region->bound, -originX, -originY); 280 281 for (uint32 c = 0; c < buffer_desc->clip_list_count; c++) { 282 region->data[c] = buffer_desc->clip_list[c]; 283 offset_rect(region->data[c], -originX, -originY); 284 } 285 286 #endif 287 288 UnlockDirect(); 289 290 return B_OK; 291 292 } 293 294 295 status_t 296 BDirectWindow::SetFullScreen(bool enable) 297 { 298 status_t status = B_ERROR; 299 if (Lock()) { 300 301 #ifdef COMPILE_FOR_R5 302 a_session->swrite_l(DW_SET_FULLSCREEN); 303 a_session->swrite_l(server_token); 304 a_session->swrite_l((int32)enable); 305 Flush(); 306 307 status_t fullScreen; 308 a_session->sread(sizeof(status_t), &fullScreen); 309 a_session->sread(sizeof(status_t), &status); 310 full_screen_enable = enable; 311 #endif 312 #ifdef __HAIKU__ 313 314 fLink->StartMessage(AS_DW_SET_FULLSCREEN); 315 fLink->Attach<int32>(server_token); // useless ? 316 fLink->Attach<bool>(enable); 317 318 int32 code; 319 if (fLink->FlushWithReply(code) == B_OK 320 && code == SERVER_TRUE) { 321 status = B_OK; 322 full_screen_enable = enable; 323 } 324 #endif 325 Unlock(); 326 327 } 328 return status; 329 } 330 331 332 bool 333 BDirectWindow::IsFullScreen() const 334 { 335 return full_screen_enable; 336 } 337 338 339 bool 340 BDirectWindow::SupportsWindowMode(screen_id id) 341 { 342 #ifdef COMPILE_FOR_R5 343 int32 result = 0; 344 _BAppServerLink_ link; 345 link.fSession->swrite_l(DW_SUPPORTS_WINDOW_MODE); 346 link.fSession->swrite_l(id.id); 347 link.fSession->sync(); 348 link.fSession->sread(sizeof(result), &result); 349 return result & true; 350 #endif 351 352 #ifdef __HAIKU__ 353 BPrivate::AppServerLink link; 354 link.StartMessage(AS_DW_SUPPORTS_WINDOW_MODE); 355 link.Attach<screen_id>(id); 356 int32 reply; 357 if (link.FlushWithReply(reply) == B_OK 358 && reply == SERVER_TRUE) 359 return true; 360 #endif 361 362 return false; 363 } 364 365 366 // Private methods 367 int32 368 BDirectWindow::DirectDeamonFunc(void *arg) 369 { 370 BDirectWindow *object = static_cast<BDirectWindow *>(arg); 371 372 while (!object->deamon_killer) { 373 // This sem is released by the app_server when our 374 // clipping region changes, or when our window is moved, 375 // resized, etc. etc. 376 while (acquire_sem(object->disable_sem) == B_INTERRUPTED) 377 ; 378 379 if (object->LockDirect()) { 380 if ((object->buffer_desc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START) 381 object->connection_enable = true; 382 383 object->in_direct_connect = true; 384 object->DirectConnected(object->buffer_desc); 385 object->in_direct_connect = false; 386 387 if ((object->buffer_desc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP) 388 object->connection_enable = false; 389 390 object->UnlockDirect(); 391 } 392 393 // The app_server then waits (with a timeout) on this sem. 394 // If we aren't quick enough to release this sem, our app 395 // will be terminated by the app_server 396 release_sem(object->disable_sem_ack); 397 } 398 399 return 0; 400 } 401 402 403 // LockDirect() and UnlockDirect() are no-op on R5. I tried to call (R5's) LockDirect() 404 // repeatedly, from the same thread and from different threads, nothing happened. 405 // I implemented them anyway, as they were the first methods I wrote 406 // in this class (As you can see, I even needed to cast away their constness 407 // to make them do something useful). 408 // They're not needed though, as the direct_deamon_thread doesn't change 409 // any shared data. They are probably here for future enhancements (see also the 410 // comment in DriverSetup() 411 bool 412 BDirectWindow::LockDirect() const 413 { 414 status_t status = B_OK; 415 416 #if DW_NEEDS_LOCKING 417 BDirectWindow *casted = const_cast<BDirectWindow *>(this); 418 419 if (atomic_add(&casted->direct_lock, 1) > 0) { 420 do { 421 status = acquire_sem(direct_sem); 422 } while (status == B_INTERRUPTED); 423 } 424 425 if (status == B_OK) { 426 casted->direct_lock_owner = find_thread(NULL); 427 casted->direct_lock_count++; 428 } 429 #endif 430 431 return status == B_OK; 432 } 433 434 435 void 436 BDirectWindow::UnlockDirect() const 437 { 438 #if DW_NEEDS_LOCKING 439 BDirectWindow *casted = const_cast<BDirectWindow *>(this); 440 441 if (atomic_add(&casted->direct_lock, -1) > 1) 442 release_sem(direct_sem); 443 444 casted->direct_lock_count--; 445 #endif 446 } 447 448 449 void 450 BDirectWindow::InitData() 451 { 452 connection_enable = false; 453 full_screen_enable = false; 454 in_direct_connect = false; 455 456 dw_init_status = 0; 457 458 direct_driver_ready = false; 459 direct_driver_type = 0; 460 direct_driver_token = 0; 461 direct_driver = NULL; 462 463 if (!Lock()) 464 return; 465 466 struct dw_sync_data sync_data; 467 status_t status = B_ERROR; 468 469 #ifdef COMPILE_FOR_R5 470 a_session->swrite_l(DW_GET_SYNC_DATA); 471 a_session->swrite_l(server_token); 472 473 Flush(); 474 475 a_session->sread(sizeof(sync_data), &sync_data); 476 a_session->sread(sizeof(status), &status); 477 #endif 478 479 #ifdef __HAIKU__ 480 fLink->StartMessage(AS_DW_GET_SYNC_DATA); 481 fLink->Attach<int32>(server_token); 482 483 int32 reply; 484 if (fLink->FlushWithReply(reply) == B_OK 485 && reply == SERVER_TRUE) { 486 fLink->Read<dw_sync_data>(&sync_data); 487 status = B_OK; 488 } 489 #endif 490 491 Unlock(); 492 493 if (status < B_OK) 494 return; 495 496 #if DW_NEEDS_LOCKING 497 direct_lock = 0; 498 direct_lock_count = 0; 499 direct_lock_owner = -1; 500 direct_lock_stack = NULL; 501 direct_sem = create_sem(1, "direct sem"); 502 if (direct_sem > 0) 503 dw_init_status |= DW_STATUS_SEM_CREATED; 504 #endif 505 506 source_clipping_area = sync_data.area; 507 disable_sem = sync_data.disableSem; 508 disable_sem_ack = sync_data.disableSemAck; 509 510 cloned_clipping_area = clone_area("Clone direct area", (void**)&buffer_desc, 511 B_ANY_ADDRESS, B_READ_AREA, source_clipping_area); 512 513 if (cloned_clipping_area > 0) { 514 dw_init_status |= DW_STATUS_AREA_CLONED; 515 516 direct_deamon_id = spawn_thread(DirectDeamonFunc, "direct deamon", 517 B_DISPLAY_PRIORITY, this); 518 519 if (direct_deamon_id > 0) { 520 deamon_killer = false; 521 if (resume_thread(direct_deamon_id) == B_OK) 522 dw_init_status |= DW_STATUS_THREAD_STARTED; 523 else 524 kill_thread(direct_deamon_id); 525 } 526 } 527 } 528 529 530 void 531 BDirectWindow::DisposeData() 532 { 533 // wait until the connection terminates: we can't destroy 534 // the object until the client receives the B_DIRECT_STOP 535 // notification, or bad things will happen 536 while (connection_enable) 537 snooze(50000); 538 539 LockDirect(); 540 541 if (dw_init_status & DW_STATUS_THREAD_STARTED) { 542 deamon_killer = true; 543 // Release this sem, otherwise the Direct deamon thread 544 // will wait forever on it 545 release_sem(disable_sem); 546 status_t retVal; 547 wait_for_thread(direct_deamon_id, &retVal); 548 } 549 550 #if DW_NEEDS_LOCKING 551 if (dw_init_status & DW_STATUS_SEM_CREATED) 552 delete_sem(direct_sem); 553 #endif 554 555 if (dw_init_status & DW_STATUS_AREA_CLONED) 556 delete_area(cloned_clipping_area); 557 } 558 559 560 status_t 561 BDirectWindow::DriverSetup() const 562 { 563 // Unimplemented in R5. 564 // This function is probably here because they wanted, in a future time, 565 // to implement graphic acceleration within BDirectWindow 566 // (in fact, there is also a BDirectDriver member in BDirectWindow, 567 // though it's not used). 568 569 return B_OK; 570 } 571 572 573 void BDirectWindow::_ReservedDirectWindow1() {} 574 void BDirectWindow::_ReservedDirectWindow2() {} 575 void BDirectWindow::_ReservedDirectWindow3() {} 576 void BDirectWindow::_ReservedDirectWindow4() {} 577