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