haiku.cpp (8180B)
1 // Copyright 2012-2022 David Robillard <d@drobilla.net> 2 // Copyright 2021-2022 Filipe Coelho <falktx@falktx.com> 3 // SPDX-License-Identifier: ISC 4 5 #include "haiku.h" 6 7 #include "../pugl-upstream/src/internal.h" 8 9 class PuglHaikuView : public BView 10 { 11 PuglView* const view; 12 13 public: 14 PuglHaikuView(PuglView* const v) 15 : BView(NULL, B_FULL_UPDATE_ON_RESIZE|B_FRAME_EVENTS|B_NAVIGABLE|B_INPUT_METHOD_AWARE), 16 view(v) {} 17 18 protected: 19 void GetPreferredSize(float* width, float* height) override 20 { 21 d_stdout("%s %i", __func__, __LINE__); 22 if (width != nullptr) 23 *width = view->frame.width; 24 if (height != nullptr) 25 *height = view->frame.height; 26 d_stdout("%s %i", __func__, __LINE__); 27 } 28 }; 29 30 class PuglHaikuWindow : public BWindow 31 { 32 PuglView* const view; 33 34 public: 35 PuglHaikuWindow(PuglView* const v) 36 : BWindow(BRect(1.0f), "DPF-Window", B_TITLED_WINDOW, 0x0), 37 view(v) {} 38 39 // protected: 40 // bool QuitRequested() override 41 // { 42 // d_stdout("%s %i", __func__, __LINE__); 43 // if (puglView->closeFunc) { 44 // puglView->closeFunc(puglView); 45 // puglView->redisplay = false; 46 // } 47 // needsQuit = false; 48 // d_stdout("%s %i", __func__, __LINE__); 49 // return true; 50 // } 51 }; 52 53 BApplication* s_app = NULL; 54 55 PuglWorldInternals* 56 puglInitWorldInternals(const PuglWorldType type, const PuglWorldFlags flags) 57 { 58 if (!s_app) { 59 status_t status; 60 s_app = new BApplication("application/x-vnd.pugl-application", &status); 61 62 if (status != B_OK) { 63 delete s_app; 64 return NULL; 65 } 66 } 67 68 PuglWorldInternals* impl = 69 (PuglWorldInternals*)calloc(1, sizeof(PuglWorldInternals)); 70 71 impl->app = s_app; 72 return impl; 73 } 74 75 void* 76 puglGetNativeWorld(PuglWorld* const world) 77 { 78 return world->impl->app; 79 } 80 81 PuglInternals* 82 puglInitViewInternals(PuglWorld* const world) 83 { 84 PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); 85 86 return impl; 87 } 88 89 PuglStatus 90 puglRealize(PuglView* const view) 91 { 92 PuglInternals* const impl = view->impl; 93 PuglStatus st = PUGL_SUCCESS; 94 95 // Ensure that we're unrealized and that a reasonable backend has been set 96 if (impl->view) { 97 return PUGL_FAILURE; 98 } 99 if (!view->backend || !view->backend->configure) { 100 return PUGL_BAD_BACKEND; 101 } 102 103 // Set the size to the default if it has not already been set 104 if (view->frame.width <= 0.0 || view->frame.height <= 0.0) { 105 const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; 106 if (!defaultSize.width || !defaultSize.height) { 107 return PUGL_BAD_CONFIGURATION; 108 } 109 110 view->frame.width = defaultSize.width; 111 view->frame.height = defaultSize.height; 112 } 113 114 // Center top-level windows if a position has not been set 115 if (!view->parent && !view->frame.x && !view->frame.y) { 116 // TODO 117 } 118 119 if (!view->parent) { 120 impl->window = new PuglHaikuWindow(view); 121 impl->window->Lock(); 122 } 123 124 impl->view = new PuglHaikuView(view); 125 126 if (view->parent) { 127 BView* const pview = (BView*)view->parent; 128 pview->AddChild(impl->view); 129 } else { 130 impl->window->AddChild(impl->view); 131 } 132 133 // Configure and create the backend 134 if ((st = view->backend->configure(view)) || (st = view->backend->create(view))) { 135 view->backend->destroy(view); 136 return st; 137 } 138 139 if (view->title) { 140 puglSetWindowTitle(view, view->title); 141 } 142 143 if (view->transientParent) { 144 puglSetTransientParent(view, view->transientParent); 145 } 146 147 puglDispatchSimpleEvent(view, PUGL_CREATE); 148 149 if (impl->window) { 150 impl->window->Unlock(); 151 } 152 153 return PUGL_SUCCESS; 154 } 155 156 PuglStatus 157 puglShow(PuglView* const view) 158 { 159 PuglInternals* const impl = view->impl; 160 if (impl->window) { 161 impl->window->Show(); 162 } else { 163 impl->view->Show(); 164 } 165 return PUGL_SUCCESS; 166 } 167 168 PuglStatus 169 puglHide(PuglView* const view) 170 { 171 PuglInternals* const impl = view->impl; 172 if (impl->window) { 173 impl->window->Hide(); 174 } else { 175 impl->view->Hide(); 176 } 177 return PUGL_SUCCESS; 178 } 179 180 void 181 puglFreeViewInternals(PuglView* const view) 182 { 183 if (view && view->impl) { 184 PuglInternals* const impl = view->impl; 185 if (view->backend) { 186 view->backend->destroy(view); 187 } 188 if (impl->view) { 189 if (impl->window) { 190 impl->window->RemoveChild(impl->view); 191 } 192 delete impl->view; 193 delete impl->window; 194 } 195 free(impl); 196 } 197 } 198 199 void 200 puglFreeWorldInternals(PuglWorld* const world) 201 { 202 // if (world->impl->app != nullptr && world->impl->app->CountWindows() == 0) { 203 // delete world->impl->app; 204 // s_app = NULL; 205 // } 206 free(world->impl); 207 } 208 209 PuglStatus 210 puglGrabFocus(PuglView*) 211 { 212 return PUGL_UNSUPPORTED; 213 } 214 215 double 216 puglGetScaleFactor(const PuglView* const view) 217 { 218 return 1.0; 219 } 220 221 double 222 puglGetTime(const PuglWorld* const world) 223 { 224 struct timespec ts; 225 clock_gettime(CLOCK_MONOTONIC, &ts); 226 return ((double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0) - 227 world->startTime; 228 } 229 230 PuglStatus 231 puglUpdate(PuglWorld* const world, const double timeout) 232 { 233 return PUGL_UNSUPPORTED; 234 } 235 236 PuglStatus 237 puglPostRedisplay(PuglView* const view) 238 { 239 return PUGL_UNSUPPORTED; 240 } 241 242 PuglStatus 243 puglPostRedisplayRect(PuglView* const view, const PuglRect rect) 244 { 245 return PUGL_UNSUPPORTED; 246 } 247 248 PuglNativeView 249 puglGetNativeView(PuglView* const view) 250 { 251 return 0; 252 } 253 254 PuglStatus 255 puglSetWindowTitle(PuglView* const view, const char* const title) 256 { 257 puglSetString(&view->title, title); 258 return PUGL_UNSUPPORTED; 259 } 260 261 PuglStatus 262 puglSetSizeHint(PuglView* const view, 263 const PuglSizeHint hint, 264 const PuglSpan width, 265 const PuglSpan height) 266 { 267 view->sizeHints[hint].width = width; 268 view->sizeHints[hint].height = height; 269 return PUGL_SUCCESS; 270 } 271 272 PuglStatus 273 puglStartTimer(PuglView* const view, const uintptr_t id, const double timeout) 274 { 275 return PUGL_UNSUPPORTED; 276 } 277 278 PuglStatus 279 puglStopTimer(PuglView* const view, const uintptr_t id) 280 { 281 return PUGL_UNSUPPORTED; 282 } 283 284 PuglStatus 285 puglPaste(PuglView* const view) 286 { 287 return PUGL_UNSUPPORTED; 288 } 289 290 PuglStatus 291 puglAcceptOffer(PuglView* const view, 292 const PuglDataOfferEvent* const offer, 293 const uint32_t typeIndex) 294 { 295 return PUGL_UNSUPPORTED; 296 } 297 298 uint32_t 299 puglGetNumClipboardTypes(const PuglView* const view) 300 { 301 return 0u; 302 } 303 304 const char* 305 puglGetClipboardType(const PuglView* const view, const uint32_t typeIndex) 306 { 307 return NULL; 308 } 309 310 const void* 311 puglGetClipboard(PuglView* const view, 312 const uint32_t typeIndex, 313 size_t* const len) 314 { 315 return NULL; 316 } 317 318 PuglStatus 319 puglSetClipboard(PuglView* const view, 320 const char* const type, 321 const void* const data, 322 const size_t len) 323 { 324 return PUGL_FAILURE; 325 } 326 327 PuglStatus 328 puglSetCursor(PuglView* const view, const PuglCursor cursor) 329 { 330 return PUGL_FAILURE; 331 } 332 333 PuglStatus 334 puglSetTransientParent(PuglView* const view, const PuglNativeView parent) 335 { 336 return PUGL_FAILURE; 337 } 338 339 PuglStatus 340 puglSetPosition(PuglView* const view, const int x, const int y) 341 { 342 return PUGL_FAILURE; 343 } 344 345 #if 0 346 PuglStatus 347 puglGrabFocus(PuglView* view) 348 { 349 view->impl->bView->MakeFocus(true); 350 return PUGL_SUCCESS; 351 } 352 353 // extras follow 354 355 void 356 puglRaiseWindow(PuglView* view) 357 { 358 } 359 360 void 361 puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) 362 { 363 bView->ResizeTo(width, height); 364 365 if (bWindow != nullptr && bWindow->LockLooper()) 366 { 367 bWindow->MoveTo(50, 50); 368 bWindow->ResizeTo(width, height); 369 370 if (! forced) 371 bWindow->Flush(); 372 373 bWindow->UnlockLooper(); 374 } 375 // TODO resizable 376 } 377 378 void setVisible(const bool yesNo) 379 { 380 if (bWindow != nullptr) 381 { 382 if (bWindow->LockLooper()) 383 { 384 if (yesNo) 385 bWindow->Show(); 386 else 387 bWindow->Hide(); 388 389 // TODO use flush? 390 bWindow->Sync(); 391 bWindow->UnlockLooper(); 392 } 393 } 394 else 395 { 396 if (yesNo) 397 bView->Show(); 398 else 399 bView->Hide(); 400 } 401 } 402 #endif