├── .editorconfig ├── AppKitPtrs.h ├── HaikuCompositor.cpp ├── HaikuCompositor.h ├── HaikuDataDeviceManager.cpp ├── HaikuDataDeviceManager.h ├── HaikuOutput.cpp ├── HaikuOutput.h ├── HaikuSeat.cpp ├── HaikuSeat.h ├── HaikuServerDecoration.cpp ├── HaikuServerDecoration.h ├── HaikuShm.cpp ├── HaikuShm.h ├── HaikuSubcompositor.cpp ├── HaikuSubcompositor.h ├── HaikuTextInput.cpp ├── HaikuTextInput.h ├── HaikuXdgPopup.cpp ├── HaikuXdgPopup.h ├── HaikuXdgPositioner.cpp ├── HaikuXdgPositioner.h ├── HaikuXdgShell.cpp ├── HaikuXdgShell.h ├── HaikuXdgSurface.cpp ├── HaikuXdgSurface.h ├── HaikuXdgToplevel.cpp ├── HaikuXdgToplevel.h ├── License.md ├── WaylandEnv.h ├── WaylandKeycodes.h ├── WaylandServer.cpp ├── WaylandServer.h ├── WlGlobal.cpp ├── WlGlobal.h ├── WlResource.cpp ├── WlResource.h ├── XkbKeymap.cpp ├── XkbKeymap.h ├── meson.build ├── protocols └── server-decoration.xml └── util └── DoublyLinkedList.h /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = tab 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /AppKitPtrs.h: -------------------------------------------------------------------------------- 1 | #ifndef _APPKITPTRS_H_ 2 | #define _APPKITPTRS_H_ 3 | 4 | #include 5 | 6 | 7 | namespace AppKitPtrs { 8 | 9 | template 10 | class LockedPtr { 11 | Base *fPtr; 12 | public: 13 | LockedPtr(): fPtr(NULL) {} 14 | LockedPtr(Base *ptr): fPtr(ptr) {if (fPtr != NULL) fPtr->LockLooper();} 15 | ~LockedPtr() {Unset();} 16 | 17 | void Unset() 18 | { 19 | if (fPtr != NULL) { 20 | fPtr->UnlockLooper(); 21 | fPtr = NULL; 22 | } 23 | } 24 | 25 | LockedPtr& operator =(Base *ptr) 26 | { 27 | if (fPtr == ptr) return *this; 28 | Unset(); 29 | fPtr = ptr; 30 | if (fPtr != NULL) fPtr->LockLooper(); 31 | return *this; 32 | } 33 | 34 | Base& operator*() const {return *fPtr;} 35 | Base* operator->() const {return fPtr;} 36 | operator Base*() const {return fPtr;} 37 | }; 38 | 39 | template 40 | LockedPtr MakeLocked(Base *ptr) 41 | { 42 | return LockedPtr(ptr); 43 | } 44 | 45 | template 46 | class ExternalPtr { 47 | private: 48 | Base *fPtr; 49 | friend class AsyncReq; 50 | template friend class ExternalPtr; 51 | 52 | public: 53 | ExternalPtr(): fPtr(NULL) {} 54 | ExternalPtr(Base *ptr): fPtr(ptr) {} 55 | template ExternalPtr(ExternalPtr other): fPtr(other.fPtr) {} 56 | void Unset() {fPtr = NULL;} 57 | ExternalPtr& operator =(Base *ptr) {fPtr = ptr; return *this;} 58 | ExternalPtr& operator =(const ExternalPtr &ptr) {fPtr = ptr.fPtr; return *this;} 59 | template void operator=(ExternalPtr other) {fPtr = other.fPtr;} 60 | template void operator=(LockedPtr other){fPtr = other.fPtr;} 61 | 62 | LockedPtr Lock() const 63 | { 64 | return LockedPtr(fPtr); 65 | } 66 | 67 | LockedPtr operator->() const {return Lock();} 68 | 69 | Base *Get() const {return fPtr;} 70 | }; 71 | 72 | template 73 | ExternalPtr MakeExternal(Args&&... args) 74 | { 75 | ExternalPtr ptr(new T(std::forward(args)...)); 76 | return ptr; 77 | } 78 | } 79 | 80 | #endif // _APPKITPTRS_H_ 81 | -------------------------------------------------------------------------------- /HaikuCompositor.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuCompositor.h" 2 | #include "HaikuSubcompositor.h" 3 | #include "HaikuShm.h" 4 | #include "HaikuXdgSurface.h" 5 | #include "HaikuXdgToplevel.h" 6 | #include "HaikuXdgPopup.h" 7 | #include "HaikuSeat.h" 8 | #include "Wayland.h" 9 | #include "WaylandEnv.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "AppKitPtrs.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | extern const struct wl_interface wl_compositor_interface; 24 | 25 | 26 | #define COMPOSITOR_VERSION 4 27 | 28 | static void Assert(bool cond) {if (!cond) abort();} 29 | 30 | 31 | //#pragma mark - HaikuRegion 32 | 33 | class HaikuRegion: public WlRegion { 34 | private: 35 | BRegion fRegion; 36 | 37 | public: 38 | virtual ~HaikuRegion() = default; 39 | static HaikuRegion *FromResource(struct wl_resource *resource) {return (HaikuRegion*)WlResource::FromResource(resource);} 40 | 41 | const BRegion &Region() {return fRegion;} 42 | 43 | void HandleAdd(int32_t x, int32_t y, int32_t width, int32_t height) final; 44 | void HandleSubtract(int32_t x, int32_t y, int32_t width, int32_t height) final; 45 | }; 46 | 47 | void HaikuRegion::HandleAdd(int32_t x, int32_t y, int32_t width, int32_t height) 48 | { 49 | width = std::min(width, 1 << 24); 50 | height = std::min(height, 1 << 24); 51 | fRegion.Include(BRect(x, y, x + width - 1, y + height - 1)); 52 | } 53 | 54 | void HaikuRegion::HandleSubtract(int32_t x, int32_t y, int32_t width, int32_t height) 55 | { 56 | width = std::min(width, 1 << 24); 57 | height = std::min(height, 1 << 24); 58 | fRegion.Exclude(BRect(x, y, x + width - 1, y + height - 1)); 59 | } 60 | 61 | 62 | //#pragma mark - HaikuCompositor 63 | 64 | class HaikuCompositor: public WlCompositor { 65 | protected: 66 | virtual ~HaikuCompositor() = default; 67 | 68 | public: 69 | void HandleCreateSurface(uint32_t id) override; 70 | void HandleCreateRegion(uint32_t id) override; 71 | }; 72 | 73 | 74 | HaikuCompositorGlobal *HaikuCompositorGlobal::Create(struct wl_display *display) 75 | { 76 | ObjectDeleter global(new(std::nothrow) HaikuCompositorGlobal()); 77 | if (!global.IsSet()) return NULL; 78 | if (!global->Init(display, &wl_compositor_interface, COMPOSITOR_VERSION)) return NULL; 79 | return global.Detach(); 80 | } 81 | 82 | void HaikuCompositorGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 83 | { 84 | HaikuCompositor *manager = new(std::nothrow) HaikuCompositor(); 85 | if (manager == NULL) { 86 | wl_client_post_no_memory(wl_client); 87 | return; 88 | } 89 | if (!manager->Init(wl_client, version, id)) { 90 | return; 91 | } 92 | } 93 | 94 | 95 | void HaikuCompositor::HandleCreateSurface(uint32_t id) 96 | { 97 | HaikuSurface *surface = HaikuSurface::Create(Client(), Version(), id); 98 | } 99 | 100 | void HaikuCompositor::HandleCreateRegion(uint32_t id) 101 | { 102 | HaikuRegion *region = new(std::nothrow) HaikuRegion(); 103 | if (region == NULL) { 104 | wl_client_post_no_memory(Client()); 105 | return; 106 | } 107 | if (!region->Init(Client(), Version(), id)) { 108 | return; 109 | } 110 | } 111 | 112 | 113 | //#pragma mark - WaylandView 114 | 115 | class WaylandView: public BView { 116 | private: 117 | friend class HaikuSurface; 118 | 119 | HaikuSurface *fSurface; 120 | uint32 fOldMouseBtns = 0; 121 | WaylandEnv *fActiveWlEnv {}; 122 | 123 | public: 124 | WaylandView(HaikuSurface *surface); 125 | virtual ~WaylandView(); 126 | 127 | HaikuSurface *Surface() {return fSurface;} 128 | 129 | void RemoveDescendantsAndSelf(); 130 | 131 | void WindowActivated(bool active) final; 132 | void MessageReceived(BMessage *msg) final; 133 | void Draw(BRect dirty); 134 | }; 135 | 136 | 137 | WaylandView::WaylandView(HaikuSurface *surface): 138 | BView(BRect(), "WaylandView", B_FOLLOW_NONE, B_WILL_DRAW | B_TRANSPARENT_BACKGROUND | B_INPUT_METHOD_AWARE), 139 | fSurface(surface) 140 | { 141 | SetViewColor(B_TRANSPARENT_COLOR); 142 | } 143 | 144 | WaylandView::~WaylandView() 145 | { 146 | if (fSurface != NULL) { 147 | debugger("[!] ~WaylandView: bad deletion"); 148 | } 149 | } 150 | 151 | void WaylandView::RemoveDescendantsAndSelf() 152 | { 153 | while (BView* child = ChildAt(0)) { 154 | WaylandView* view = dynamic_cast(child); 155 | view->RemoveDescendantsAndSelf(); 156 | } 157 | 158 | if (fActiveWlEnv != NULL) 159 | WaylandEnv::Wait(&fActiveWlEnv, Looper()); 160 | RemoveSelf(); 161 | } 162 | 163 | void WaylandView::WindowActivated(bool active) 164 | { 165 | WaylandEnv wlEnv(this, &fActiveWlEnv); 166 | HaikuSeatGlobal *seat = HaikuGetSeat(fSurface->Client()); 167 | if (seat == NULL) return; 168 | 169 | if (fSurface->Subsurface() != NULL) { 170 | return; 171 | } 172 | 173 | seat->SetKeyboardFocus(fSurface, active); 174 | } 175 | 176 | void WaylandView::MessageReceived(BMessage *msg) 177 | { 178 | { 179 | WaylandEnv wlEnv(this, &fActiveWlEnv); 180 | HaikuSeatGlobal *seat = HaikuGetSeat(fSurface->Client()); 181 | if (seat != NULL) { 182 | bool isPointerMessage = true; 183 | BPoint where; 184 | if (msg->WasDropped()) { 185 | where = msg->DropPoint(); 186 | AppKitPtrs::LockedPtr(this)->ConvertFromScreen(&where); 187 | } else if (msg->FindPoint("be:view_where", &where) < B_OK) { 188 | isPointerMessage = false; 189 | } 190 | HaikuSurface *surface = fSurface; 191 | while (isPointerMessage && !surface->InputRgnContains(where) && surface->Subsurface() != NULL) { 192 | surface = surface->Subsurface()->Parent(); 193 | } 194 | if (surface != fSurface) { 195 | BPoint offset = AppKitPtrs::LockedPtr(fSurface->View())->Frame().LeftTop() - AppKitPtrs::LockedPtr(surface->View())->Frame().LeftTop(); 196 | msg->ReplacePoint("be:view_where", where + offset); 197 | } 198 | if (seat->MessageReceived(surface, msg)) { 199 | return; 200 | } 201 | } 202 | } 203 | BView::MessageReceived(msg); 204 | } 205 | 206 | void WaylandView::Draw(BRect dirty) 207 | { 208 | WaylandEnv wlEnv(this, &fActiveWlEnv); 209 | 210 | BBitmap *bmp = fSurface->Bitmap(); 211 | if (bmp != NULL) { 212 | auto viewLocked = AppKitPtrs::LockedPtr(this); 213 | drawing_mode mode; 214 | switch (bmp->ColorSpace()) { 215 | case B_RGBA64: 216 | case B_RGBA32: 217 | case B_RGBA15: 218 | case B_RGBA64_BIG: 219 | case B_RGBA32_BIG: 220 | case B_RGBA15_BIG: 221 | mode = B_OP_ALPHA; 222 | break; 223 | default: 224 | mode = B_OP_COPY; 225 | break; 226 | } 227 | if (mode == B_OP_ALPHA && fSurface->fState.opaqueRgn.has_value()) { 228 | viewLocked->ConstrainClippingRegion(&fSurface->fState.opaqueRgn.value()); 229 | viewLocked->SetDrawingMode(B_OP_COPY); 230 | viewLocked->DrawBitmap(bmp); 231 | BRegion remaining = viewLocked->Bounds(); 232 | remaining.Exclude(&fSurface->fState.opaqueRgn.value()); 233 | viewLocked->ConstrainClippingRegion(&remaining); 234 | } 235 | viewLocked->SetDrawingMode(mode); 236 | viewLocked->DrawBitmap(bmp); 237 | } 238 | 239 | fSurface->CallFrameCallbacks(); 240 | } 241 | 242 | 243 | //#pragma mark - HaikuSurface 244 | 245 | HaikuSurface::FrameCallback *HaikuSurface::FrameCallback::Create(struct wl_client *client, uint32_t version, uint32_t id) 246 | { 247 | FrameCallback *callback = new(std::nothrow) FrameCallback(); 248 | if (!callback->Init(client, version, id)) { 249 | return NULL; 250 | } 251 | return callback; 252 | } 253 | 254 | HaikuSurface *HaikuSurface::Create(struct wl_client *client, uint32_t version, uint32_t id) 255 | { 256 | HaikuSurface *surface = new(std::nothrow) HaikuSurface(); 257 | if (!surface->Init(client, version, id)) { 258 | return NULL; 259 | } 260 | return surface; 261 | } 262 | 263 | HaikuSurface::~HaikuSurface() 264 | { 265 | HaikuSeatGlobal *seat = HaikuGetSeat(Client()); 266 | if (seat != NULL) { 267 | seat->SetPointerFocus(this, false, BMessage()); 268 | seat->SetKeyboardFocus(this, false); 269 | } 270 | 271 | if (fView != NULL) { 272 | Detach(); 273 | } 274 | 275 | for (HaikuSubsurface *subsurface = SurfaceList().First(); subsurface != NULL; subsurface = SurfaceList().GetNext(subsurface)) { 276 | subsurface->fParent = NULL; 277 | } 278 | } 279 | 280 | void HaikuSurface::AttachWindow(BWindow *window) 281 | { 282 | Assert(fView == NULL); 283 | 284 | fView = new WaylandView(this); 285 | window->AddChild(fView); 286 | fView->MakeFocus(); 287 | } 288 | 289 | void HaikuSurface::AttachView(BView *view) 290 | { 291 | if (view == NULL) { 292 | fprintf(stderr, "[!] HaikuSurface::AttachView(): view == NULL\n"); 293 | return; 294 | } 295 | fView = new WaylandView(this); 296 | view->AddChild(fView); 297 | } 298 | 299 | void HaikuSurface::AttachViewsToEarlierSubsurfaces() 300 | { 301 | if (fView == NULL) { 302 | fprintf(stderr, "[!] HaikuSurface::AttachViewsToEarlierSubsurfaces(): fView == NULL\n"); 303 | return; 304 | } 305 | for (HaikuSubsurface *subsurface = SurfaceList().First(); subsurface != NULL; subsurface = SurfaceList().GetNext(subsurface)) { 306 | subsurface->Surface()->AttachView(fView); 307 | } 308 | } 309 | 310 | void HaikuSurface::Detach() 311 | { 312 | if (fView == NULL) { 313 | return; 314 | } 315 | 316 | fView->LockLooper(); 317 | BLooper *looper = fView->Looper(); 318 | fView->RemoveDescendantsAndSelf(); 319 | 320 | fView->fSurface = NULL; 321 | delete fView; 322 | fView = NULL; 323 | 324 | if (looper != NULL) { 325 | looper->Unlock(); 326 | } 327 | } 328 | 329 | void HaikuSurface::Invalidate() 330 | { 331 | if (fView == NULL) { 332 | return; 333 | } 334 | auto viewLocked = AppKitPtrs::LockedPtr(fView); 335 | if (fSubsurface != NULL) { 336 | viewLocked->Invalidate(); 337 | } else { 338 | viewLocked->Invalidate(&fDirty); 339 | } 340 | fDirty.MakeEmpty(); 341 | } 342 | 343 | void HaikuSurface::CallFrameCallbacks() 344 | { 345 | while (!fState.frameCallbacks.IsEmpty()) { 346 | FrameCallback *callback = fState.frameCallbacks.RemoveHead(); 347 | callback->SendDone(system_time()/1000); 348 | callback->Destroy(); 349 | } 350 | } 351 | 352 | void HaikuSurface::SetHook(Hook *hook) 353 | { 354 | if (hook != NULL) {hook->fBase = this;} 355 | fHook.SetTo(hook); 356 | } 357 | 358 | 359 | void HaikuSurface::HandleAttach(struct wl_resource *buffer_resource, int32_t dx, int32_t dy) 360 | { 361 | fPendingState.buffer = HaikuShmBuffer::FromResource(buffer_resource); 362 | fPendingState.dx = dx; 363 | fPendingState.dy = dy; 364 | fPendingFields |= (1 << fieldBuffer) | (1 << fieldOffset); 365 | } 366 | 367 | void HaikuSurface::HandleDamage(int32_t x, int32_t y, int32_t width, int32_t height) 368 | { 369 | width = std::min(width, 1 << 24); 370 | height = std::min(height, 1 << 24); 371 | fDirty.Include(BRect(x, y, x + width - 1, y + height - 1)); 372 | } 373 | 374 | void HaikuSurface::HandleFrame(uint32_t callback_id) 375 | { 376 | fPendingState.frameCallbacks.Insert(FrameCallback::Create(Client(), 1, callback_id)); 377 | fPendingFields |= (1 << fieldFrameCallbacks); 378 | } 379 | 380 | void HaikuSurface::HandleSetOpaqueRegion(struct wl_resource *region_resource) 381 | { 382 | if (region_resource == NULL) { 383 | fPendingState.opaqueRgn.reset(); 384 | } else { 385 | fPendingState.opaqueRgn.emplace(HaikuRegion::FromResource(region_resource)->Region()); 386 | } 387 | fPendingFields |= (1 << fieldOpaqueRgn); 388 | } 389 | 390 | void HaikuSurface::HandleSetInputRegion(struct wl_resource *region_resource) 391 | { 392 | if (region_resource == NULL) { 393 | fPendingState.inputRgn.reset(); 394 | } else { 395 | fPendingState.inputRgn.emplace(HaikuRegion::FromResource(region_resource)->Region()); 396 | } 397 | fPendingFields |= (1 << fieldInputRgn); 398 | } 399 | 400 | void HaikuSurface::HandleCommit() 401 | { 402 | //printf("HaikuSurface::HandleCommit()\n"); 403 | 404 | for (;;) { 405 | uint32 field = std::countr_zero(fPendingFields); 406 | if (field >= 32) { 407 | break; 408 | } 409 | fPendingFields &= ~(1U << field); 410 | switch (field) { 411 | case fieldBuffer: 412 | if (fState.buffer != NULL && fState.buffer != fPendingState.buffer) { 413 | fState.buffer->SendRelease(); 414 | } 415 | fState.buffer = fPendingState.buffer; 416 | break; 417 | case fieldOffset: 418 | fState.dx = fPendingState.dx; 419 | fState.dy = fPendingState.dy; 420 | break; 421 | case fieldTransform: 422 | fState.transform = fPendingState.transform; 423 | break; 424 | case fieldScale: 425 | fState.scale = fPendingState.scale; 426 | break; 427 | case fieldOpaqueRgn: 428 | fState.opaqueRgn = std::move(fPendingState.opaqueRgn); 429 | break; 430 | case fieldInputRgn: 431 | fState.inputRgn = std::move(fPendingState.inputRgn); 432 | break; 433 | case fieldFrameCallbacks: 434 | fState.frameCallbacks.TakeFrom(&fPendingState.frameCallbacks); 435 | break; 436 | } 437 | } 438 | 439 | if (View() != NULL && View()->Window() != NULL) { 440 | auto viewLocked = AppKitPtrs::LockedPtr(View()); 441 | if (fSubsurface != NULL) { 442 | viewLocked->MoveTo(fSubsurface->GetState().x, fSubsurface->GetState().y); 443 | } 444 | if (Bitmap() != NULL) { 445 | viewLocked->ResizeTo(Bitmap()->Bounds().Width(), Bitmap()->Bounds().Height()); 446 | } 447 | Invalidate(); 448 | } 449 | if (fHook.IsSet()) { 450 | fHook->HandleCommit(); 451 | } 452 | } 453 | 454 | void HaikuSurface::HandleSetBufferTransform(int32_t transform) 455 | { 456 | fPendingState.transform = transform; 457 | fPendingFields |= (1 << fieldTransform); 458 | } 459 | 460 | void HaikuSurface::HandleSetBufferScale(int32_t scale) 461 | { 462 | fPendingState.scale = scale; 463 | fPendingFields |= (1 << fieldScale); 464 | } 465 | 466 | void HaikuSurface::HandleDamageBuffer(int32_t x, int32_t y, int32_t width, int32_t height) 467 | { 468 | width = std::min(width, 1 << 24); 469 | height = std::min(height, 1 << 24); 470 | fDirty.Include(BRect(x, y, x + width - 1, y + height - 1)); 471 | } 472 | 473 | void HaikuSurface::HandleOffset(int32_t x, int32_t y) 474 | { 475 | fPendingState.dx = x; 476 | fPendingState.dy = y; 477 | fPendingFields |= (1 << fieldOffset); 478 | } 479 | -------------------------------------------------------------------------------- /HaikuCompositor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Wayland.h" 4 | #include "WlGlobal.h" 5 | #include "HaikuSubcompositor.h" 6 | #include "HaikuShm.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | class HaikuXdgSurface; 14 | class HaikuServerDecoration; 15 | class WaylandView; 16 | class BBitmap; 17 | class BWindow; 18 | class BView; 19 | 20 | 21 | class HaikuCompositorGlobal: public WlGlocal { 22 | public: 23 | static HaikuCompositorGlobal *Create(struct wl_display *display); 24 | virtual ~HaikuCompositorGlobal() = default; 25 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) override; 26 | }; 27 | 28 | 29 | class HaikuSurface: public WlSurface { 30 | public: 31 | class Hook { 32 | private: 33 | friend class HaikuSurface; 34 | HaikuSurface *fBase{}; 35 | public: 36 | virtual ~Hook() = default; 37 | HaikuSurface *Base() {return fBase;} 38 | virtual void HandleCommit() = 0; 39 | }; 40 | 41 | private: 42 | friend class HaikuXdgSurface; 43 | friend class HaikuXdgToplevel; 44 | friend class HaikuServerDecoration; 45 | friend class HaikuSubsurface; 46 | friend class WaylandView; 47 | 48 | class FrameCallback: public WlCallback { 49 | private: 50 | DoublyLinkedListLink fLink; 51 | 52 | public: 53 | typedef DoublyLinkedList> List; 54 | 55 | static FrameCallback *Create(struct wl_client *client, uint32_t version, uint32_t id); 56 | virtual ~FrameCallback() = default; 57 | }; 58 | 59 | enum StateField { 60 | fieldBuffer, 61 | fieldOffset, 62 | fieldTransform, 63 | fieldScale, 64 | fieldOpaqueRgn, 65 | fieldInputRgn, 66 | fieldFrameCallbacks 67 | }; 68 | 69 | struct State { 70 | BReference buffer; 71 | int32_t dx, dy; 72 | int32_t transform = WlOutput::transformNormal; 73 | int32_t scale = 1; 74 | std::optional opaqueRgn; 75 | std::optional inputRgn; 76 | FrameCallback::List frameCallbacks; 77 | }; 78 | 79 | ObjectDeleter fHook; 80 | 81 | State fState{}; 82 | State fPendingState{}; 83 | uint32 fPendingFields{}; 84 | BRegion fDirty; 85 | WaylandView *fView{}; 86 | HaikuXdgSurface *fXdgSurface{}; 87 | HaikuServerDecoration *fServerDecoration{}; 88 | HaikuSubsurface *fSubsurface{}; 89 | 90 | HaikuSubsurface::SurfaceList fSurfaceList; 91 | 92 | public: 93 | static HaikuSurface *Create(struct wl_client *client, uint32_t version, uint32_t id); 94 | static HaikuSurface *FromResource(struct wl_resource *resource) {return (HaikuSurface*)WlResource::FromResource(resource);} 95 | virtual ~HaikuSurface(); 96 | 97 | BView *View() {return (BView*)fView;} 98 | BBitmap *Bitmap() {return fState.buffer == NULL ? NULL : &fState.buffer->Bitmap();} 99 | bool InputRgnContains(BPoint p) {return !fState.inputRgn ? true : fState.inputRgn->Contains(p);} 100 | void GetOffset(int32_t &x, int32_t &y) {x = fState.dx; y = fState.dy;} 101 | HaikuXdgSurface *XdgSurface() {return fXdgSurface;} 102 | HaikuSubsurface *Subsurface() {return fSubsurface;} 103 | HaikuServerDecoration *ServerDecoration() {return fServerDecoration;} 104 | HaikuSubsurface::SurfaceList &SurfaceList() {return fSurfaceList;} 105 | void AttachWindow(BWindow *window); 106 | void AttachView(BView *view); 107 | void AttachViewsToEarlierSubsurfaces(); 108 | void Detach(); 109 | void Invalidate(); 110 | void CallFrameCallbacks(); 111 | 112 | void SetHook(Hook *hook); 113 | 114 | void HandleAttach(struct wl_resource *buffer_resource, int32_t dx, int32_t dy) override; 115 | void HandleDamage(int32_t x, int32_t y, int32_t width, int32_t height) override; 116 | void HandleFrame(uint32_t callback) override; 117 | void HandleSetOpaqueRegion(struct wl_resource *region_resource) override; 118 | void HandleSetInputRegion(struct wl_resource *region_resource) override; 119 | void HandleCommit() override; 120 | void HandleSetBufferTransform(int32_t transform) override; 121 | void HandleSetBufferScale(int32_t scale) override; 122 | void HandleDamageBuffer(int32_t x, int32_t y, int32_t width, int32_t height) override; 123 | void HandleOffset(int32_t x, int32_t y) override; 124 | }; 125 | -------------------------------------------------------------------------------- /HaikuDataDeviceManager.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuDataDeviceManager.h" 2 | #include "HaikuSeat.h" 3 | #include "WaylandServer.h" 4 | #include "AppKitPtrs.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | extern const struct wl_interface wl_data_device_manager_interface; 18 | 19 | 20 | enum { 21 | DATA_DEVICE_MANAGER_VERSION = 3, 22 | }; 23 | 24 | 25 | //#pragma mark - HaikuDataSource 26 | 27 | void HaikuDataSource::ConvertToHaikuMessage(BMessage &dstMsg, const BMessage &srcMsg) 28 | { 29 | char *name; 30 | type_code type; 31 | int32 count; 32 | const void *val; 33 | ssize_t size; 34 | for (int32 i = 0; srcMsg.GetInfo(B_MIME_TYPE, i, &name, &type, &count) == B_OK; i++) { 35 | srcMsg.FindData(name, B_MIME_TYPE, 0, &val, &size); 36 | if (strcmp(name, "text/plain;charset=utf-8") == 0) { 37 | dstMsg.AddData("text/plain", B_MIME_TYPE, val, size); 38 | } else if (strcmp(name, "text/plain") == 0) { 39 | // drop 40 | } else if (strcmp(name, "text/uri-list") == 0) { 41 | BString str((const char*)val, size); 42 | int32 pos = 0; 43 | while (pos < str.Length()) { 44 | int32 nextPos = str.FindFirst("\r\n", pos); 45 | if (nextPos < 0) { 46 | nextPos = str.Length(); 47 | } 48 | if (str[pos] != '#') { 49 | if (str.FindFirst("file://", pos) == pos) { 50 | BString path; 51 | str.CopyInto(path, pos + strlen("file://"), nextPos - pos - strlen("file://")); 52 | printf("path: \"%s\"\n", path.String()); 53 | BEntry entry(path); 54 | if (entry.InitCheck() >= B_OK) { 55 | entry_ref ref; 56 | entry.GetRef(&ref); 57 | dstMsg.AddRef("refs", &ref); 58 | } 59 | } 60 | } 61 | pos = nextPos + strlen("\r\n"); 62 | } 63 | 64 | } else { 65 | dstMsg.AddData(name, B_MIME_TYPE, val, size); 66 | } 67 | } 68 | } 69 | HaikuDataSource::~HaikuDataSource() 70 | { 71 | if (fDataDevice != NULL && fDataDevice->fDataSource == this) 72 | fDataDevice->fDataSource = NULL; 73 | } 74 | 75 | status_t HaikuDataSource::ReadData(std::vector &data, const char *mimeType) 76 | { 77 | int pipes[2]; 78 | if (pipe(pipes) != 0) { 79 | return B_ERROR; 80 | } 81 | 82 | FileDescriptorCloser readPipe(pipes[0]); 83 | FileDescriptorCloser writePipe(pipes[1]); 84 | 85 | if (fcntl(readPipe.Get(), F_SETFD, FD_CLOEXEC) == -1 || 86 | fcntl(writePipe.Get(), F_SETFD, FD_CLOEXEC) == -1) { 87 | return B_ERROR; 88 | } 89 | 90 | int flags = fcntl(readPipe.Get(), F_GETFL, 0); 91 | if (fcntl(readPipe.Get(), F_SETFL, flags | O_NONBLOCK) == -1) { 92 | return B_ERROR; 93 | } 94 | 95 | SendSend(mimeType, writePipe.Get()); 96 | writePipe.Unset(); 97 | 98 | data.clear(); 99 | 100 | constexpr size_t bufferSize = 1024; 101 | std::vector buffer(bufferSize); 102 | 103 | struct pollfd pfd; 104 | pfd.fd = readPipe.Get(); 105 | pfd.events = POLLIN; 106 | 107 | while (true) { 108 | int ret = poll(&pfd, 1, 20); 109 | 110 | if (ret > 0 && (pfd.revents & POLLIN)) { 111 | ssize_t readLen = read(readPipe.Get(), buffer.data(), bufferSize); 112 | if (readLen < 0) { 113 | if (errno == EAGAIN || errno == EWOULDBLOCK) { 114 | continue; 115 | } 116 | return B_ERROR; 117 | } 118 | if (readLen == 0) { 119 | break; 120 | } 121 | data.insert(data.end(), buffer.begin(), buffer.begin() + readLen); 122 | } else if (ret == 0) { 123 | break; 124 | } else { 125 | return B_ERROR; 126 | } 127 | } 128 | return B_OK; 129 | } 130 | 131 | BMessage *HaikuDataSource::ToMessage() 132 | { 133 | ObjectDeleter msg(new BMessage(B_SIMPLE_DATA)); 134 | for (auto &mimeType: fMimeTypes) { 135 | if (mimeType == "DELETE" || mimeType == "SAVE_TARGETS") { 136 | continue; 137 | } 138 | std::vector data; 139 | ReadData(data, mimeType.c_str()); 140 | msg->AddData(mimeType.c_str(), B_MIME_TYPE, data.data(), data.size()); 141 | } 142 | ObjectDeleter dstMsg(new BMessage(B_SIMPLE_DATA)); 143 | ConvertToHaikuMessage(*dstMsg.Get(), *msg.Get()); 144 | return dstMsg.Detach(); 145 | } 146 | 147 | void HaikuDataSource::HandleOffer(const char *mimeType) 148 | { 149 | fMimeTypes.emplace(mimeType); 150 | } 151 | 152 | void HaikuDataSource::HandleSetActions(uint32_t dndActions) 153 | { 154 | } 155 | 156 | 157 | //#pragma mark - HaikuDataOffer 158 | 159 | HaikuDataOffer *HaikuDataOffer::Create(HaikuDataDevice *dataDevice, const BMessage &data) 160 | { 161 | HaikuDataOffer *dataOffer = new(std::nothrow) HaikuDataOffer(); 162 | if (dataOffer == NULL) { 163 | wl_client_post_no_memory(dataDevice->Client()); 164 | return NULL; 165 | } 166 | if (!dataOffer->Init(dataDevice->Client(), dataDevice->Version(), 0)) { 167 | return NULL; 168 | } 169 | 170 | dataOffer->fData = data; 171 | 172 | dataDevice->SendDataOffer(dataOffer->ToResource()); 173 | 174 | char *name; 175 | type_code type; 176 | int32 count; 177 | const void *val; 178 | ssize_t size; 179 | for (int32 i = 0; data.GetInfo(B_MIME_TYPE, i, &name, &type, &count) == B_OK; i++) { 180 | data.FindData(name, B_MIME_TYPE, 0, &val, &size); 181 | dataOffer->SendOffer(name); 182 | if (strcmp(name, "text/plain") == 0 && !data.HasData("text/plain;charset=utf-8", B_MIME_TYPE)) { 183 | dataOffer->SendOffer("text/plain;charset=utf-8"); 184 | } 185 | } 186 | 187 | dataOffer->SendAction(0); 188 | dataOffer->SendSourceActions(7); 189 | return dataOffer; 190 | } 191 | 192 | void HaikuDataOffer::HandleAccept(uint32_t serial, const char *mime_type) 193 | { 194 | } 195 | 196 | void HaikuDataOffer::HandleReceive(const char *mimeType, int32_t fd) 197 | { 198 | if (strcmp(mimeType, "text/plain;charset=utf-8") == 0) { 199 | mimeType = "text/plain"; 200 | } 201 | const uint8 *val; 202 | ssize_t size; 203 | fData.FindData(mimeType, B_MIME_TYPE, 0, (const void**)&val, &size); 204 | while (size > 0) { 205 | ssize_t sizeWritten = write(fd, val, size); 206 | if (sizeWritten < 0) break; 207 | val += sizeWritten; 208 | size -= sizeWritten; 209 | } 210 | close(fd); 211 | } 212 | 213 | void HaikuDataOffer::HandleFinish() 214 | { 215 | } 216 | 217 | void HaikuDataOffer::HandleSetActions(uint32_t dnd_actions, uint32_t preferred_action) 218 | { 219 | } 220 | 221 | 222 | //#pragma mark - HaikuDataDevice 223 | 224 | HaikuDataDevice::ClipboardWatcher::ClipboardWatcher(): BHandler("clipboardWatcher") 225 | {} 226 | 227 | void HaikuDataDevice::ClipboardWatcher::MessageReceived(BMessage *msg) 228 | { 229 | switch (msg->what) { 230 | case B_CLIPBOARD_CHANGED: { 231 | AutoLocker clipboard(be_clipboard); 232 | if (!clipboard.IsLocked()) return; 233 | 234 | if (Base().fDataSource != NULL) { 235 | Base().fDataSource->SendCancelled(); 236 | Base().fDataSource = NULL; 237 | } 238 | 239 | HaikuDataDevice *dataDevice = &Base(); 240 | HaikuDataOffer *dataOffer = HaikuDataOffer::Create(dataDevice, *be_clipboard->Data()); 241 | dataDevice->SendSelection(dataOffer->ToResource()); 242 | return; 243 | } 244 | } 245 | return BHandler::MessageReceived(msg); 246 | } 247 | 248 | 249 | HaikuDataDevice *HaikuDataDevice::Create(struct wl_client *client, uint32_t version, uint32_t id, struct wl_resource *seat) 250 | { 251 | HaikuDataDevice *dataDevice = new(std::nothrow) HaikuDataDevice(); 252 | if (dataDevice == NULL) { 253 | wl_client_post_no_memory(client); 254 | return NULL; 255 | } 256 | if (!dataDevice->Init(client, version, id)) { 257 | return NULL; 258 | } 259 | dataDevice->fSeat = HaikuSeat::FromResource(seat); 260 | dataDevice->fSeat->GetGlobal()->fDataDevice = dataDevice; 261 | 262 | AppKitPtrs::LockedPtr(&gServerHandler)->Looper()->AddHandler(&dataDevice->fClipboardWatcher); 263 | be_clipboard->StartWatching(BMessenger(&dataDevice->fClipboardWatcher)); 264 | 265 | return dataDevice; 266 | } 267 | 268 | HaikuDataDevice::~HaikuDataDevice() 269 | { 270 | be_clipboard->StopWatching(BMessenger(&fClipboardWatcher)); 271 | AppKitPtrs::LockedPtr(&gServerHandler)->Looper()->RemoveHandler(&fClipboardWatcher); 272 | } 273 | 274 | void HaikuDataDevice::HandleStartDrag(struct wl_resource *_source, struct wl_resource *_origin, struct wl_resource *_icon, uint32_t serial) 275 | { 276 | } 277 | 278 | void HaikuDataDevice::HandleSetSelection(struct wl_resource *_source, uint32_t serial) 279 | { 280 | if (_source == NULL) return; 281 | 282 | HaikuDataSource *source = HaikuDataSource::FromResource(_source); 283 | 284 | 285 | ObjectDeleter srcMsg(source->ToMessage()); 286 | 287 | AutoLocker clipboard(be_clipboard); 288 | if (!clipboard.IsLocked()) return; 289 | if (clipboard.Get()->Clear() != B_OK) return; 290 | BMessage* clipper = be_clipboard->Data(); 291 | if (clipper == NULL) return; 292 | *clipper = *srcMsg.Get(); 293 | clipper->what = B_MIME_DATA; 294 | clipboard.Get()->Commit(); 295 | 296 | fDataSource = source; 297 | source->fDataDevice = this; 298 | } 299 | 300 | 301 | //#pragma mark - HaikuDataDeviceManager 302 | 303 | class HaikuDataDeviceManager: public WlDataDeviceManager { 304 | private: 305 | virtual ~HaikuDataDeviceManager() = default; 306 | 307 | public: 308 | void HandleCreateDataSource(uint32_t id) final; 309 | void HandleGetDataDevice(uint32_t id, struct wl_resource *seat) final; 310 | }; 311 | 312 | 313 | HaikuDataDeviceManagerGlobal *HaikuDataDeviceManagerGlobal::Create(struct wl_display *display) 314 | { 315 | ObjectDeleter global(new(std::nothrow) HaikuDataDeviceManagerGlobal()); 316 | if (!global.IsSet()) return NULL; 317 | if (!global->Init(display, &wl_data_device_manager_interface, DATA_DEVICE_MANAGER_VERSION)) return NULL; 318 | return global.Detach(); 319 | } 320 | 321 | void HaikuDataDeviceManagerGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 322 | { 323 | HaikuDataDeviceManager *manager = new(std::nothrow) HaikuDataDeviceManager(); 324 | if (manager == NULL) { 325 | wl_client_post_no_memory(wl_client); 326 | return; 327 | } 328 | if (!manager->Init(wl_client, version, id)) { 329 | return; 330 | } 331 | } 332 | 333 | 334 | void HaikuDataDeviceManager::HandleCreateDataSource(uint32_t id) 335 | { 336 | HaikuDataSource *dataSource = new(std::nothrow) HaikuDataSource(); 337 | if (dataSource == NULL) { 338 | wl_client_post_no_memory(Client()); 339 | return; 340 | } 341 | if (!dataSource->Init(Client(), Version(), id)) { 342 | return; 343 | } 344 | } 345 | 346 | void HaikuDataDeviceManager::HandleGetDataDevice(uint32_t id, struct wl_resource *seat) 347 | { 348 | HaikuDataDevice *dataDevice = HaikuDataDevice::Create(Client(), Version(), id, seat); 349 | } 350 | -------------------------------------------------------------------------------- /HaikuDataDeviceManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Wayland.h" 3 | #include "WlGlobal.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | class HaikuSeat; 12 | class HaikuDataDevice; 13 | 14 | class HaikuDataSource: public WlDataSource { 15 | private: 16 | friend class HaikuDataOffer; 17 | friend class HaikuDataDevice; 18 | 19 | HaikuDataDevice *fDataDevice{}; 20 | std::set fMimeTypes; 21 | 22 | static void ConvertToHaikuMessage(BMessage &dstMsg, const BMessage &srcMsg); 23 | 24 | 25 | public: 26 | static HaikuDataSource *FromResource(struct wl_resource *resource) {return (HaikuDataSource*)WlResource::FromResource(resource);} 27 | virtual ~HaikuDataSource(); 28 | 29 | std::set &MimeTypes() {return fMimeTypes;} 30 | 31 | status_t ReadData(std::vector &data, const char *mimeType); 32 | BMessage *ToMessage(); 33 | 34 | void HandleOffer(const char *mimeType) final; 35 | void HandleSetActions(uint32_t dndActions) final; 36 | }; 37 | 38 | class HaikuDataOffer: public WlDataOffer { 39 | private: 40 | BMessage fData; 41 | 42 | public: 43 | static HaikuDataOffer *Create(HaikuDataDevice *dataDevice, const BMessage &data); 44 | static HaikuDataOffer *FromResource(struct wl_resource *resource) {return (HaikuDataOffer*)WlResource::FromResource(resource);} 45 | 46 | void HandleAccept(uint32_t serial, const char *mime_type) final; 47 | void HandleReceive(const char *mime_type, int32_t fd) final; 48 | void HandleFinish() final; 49 | void HandleSetActions(uint32_t dnd_actions, uint32_t preferred_action) final; 50 | }; 51 | 52 | class HaikuDataDevice: public WlDataDevice { 53 | private: 54 | friend class HaikuDataSource; 55 | 56 | HaikuSeat *fSeat; 57 | HaikuDataSource *fDataSource; 58 | 59 | class ClipboardWatcher: public BHandler { 60 | public: 61 | inline HaikuDataDevice &Base() {return *(HaikuDataDevice*)((char*)this - offsetof(HaikuDataDevice, fClipboardWatcher));} 62 | 63 | ClipboardWatcher(); 64 | virtual ~ClipboardWatcher() = default; 65 | void MessageReceived(BMessage *msg) final; 66 | } fClipboardWatcher; 67 | 68 | public: 69 | static HaikuDataDevice *Create(struct wl_client *client, uint32_t version, uint32_t id, struct wl_resource *seat); 70 | static HaikuDataDevice *FromResource(struct wl_resource *resource) {return (HaikuDataDevice*)WlResource::FromResource(resource);} 71 | virtual ~HaikuDataDevice(); 72 | 73 | void HandleStartDrag(struct wl_resource *source, struct wl_resource *origin, struct wl_resource *icon, uint32_t serial) final; 74 | void HandleSetSelection(struct wl_resource *source, uint32_t serial) final; 75 | }; 76 | 77 | class HaikuDataDeviceManagerGlobal: public WlGlocal { 78 | public: 79 | static HaikuDataDeviceManagerGlobal *Create(struct wl_display *display); 80 | virtual ~HaikuDataDeviceManagerGlobal() = default; 81 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) override; 82 | }; 83 | -------------------------------------------------------------------------------- /HaikuOutput.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuOutput.h" 2 | #include 3 | #include 4 | 5 | extern const struct wl_interface wl_output_interface; 6 | 7 | 8 | enum { 9 | OUTPUT_VERSION = 3, 10 | }; 11 | 12 | 13 | class HaikuOutput: public WlOutput { 14 | protected: 15 | virtual ~HaikuOutput() = default; 16 | }; 17 | 18 | 19 | HaikuOutputGlobal *HaikuOutputGlobal::Create(struct wl_display *display) 20 | { 21 | ObjectDeleter global(new(std::nothrow) HaikuOutputGlobal()); 22 | if (!global.IsSet()) return NULL; 23 | if (!global->Init(display, &wl_output_interface, OUTPUT_VERSION)) return NULL; 24 | return global.Detach(); 25 | } 26 | 27 | void HaikuOutputGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 28 | { 29 | HaikuOutput *output = new(std::nothrow) HaikuOutput(); 30 | if (output == NULL) { 31 | wl_client_post_no_memory(wl_client); 32 | return; 33 | } 34 | if (!output->Init(wl_client, version, id)) { 35 | return; 36 | } 37 | 38 | BScreen screen; 39 | int32_t width = (int32_t)screen.Frame().Width() + 1; 40 | int32_t height = (int32_t)screen.Frame().Height() + 1; 41 | output->SendGeometry(0, 0, (float)width * 0.3528, (float)height * 0.3528, WlOutput::subpixelUnknown, "Unknown make", "Unknown model", WlOutput::transformNormal); 42 | output->SendMode(WlOutput::modeCurrent | WlOutput::modePreferred, width, height, 60000); 43 | output->SendScale(1); 44 | output->SendDone(); 45 | } 46 | -------------------------------------------------------------------------------- /HaikuOutput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Wayland.h" 3 | #include "WlGlobal.h" 4 | 5 | 6 | class HaikuOutputGlobal: public WlGlocal { 7 | public: 8 | static HaikuOutputGlobal *Create(struct wl_display *display); 9 | virtual ~HaikuOutputGlobal() = default; 10 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) override; 11 | }; 12 | -------------------------------------------------------------------------------- /HaikuSeat.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuSeat.h" 2 | #include "HaikuCompositor.h" 3 | #include "HaikuXdgSurface.h" 4 | #include "HaikuXdgToplevel.h" 5 | #include "HaikuDataDeviceManager.h" 6 | #include "WaylandKeycodes.h" 7 | #include "XkbKeymap.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "AppKitPtrs.h" 15 | 16 | #include 17 | #include 18 | 19 | extern const struct wl_interface wl_seat_interface; 20 | 21 | 22 | enum { 23 | SEAT_VERSION = 8, 24 | }; 25 | 26 | static HaikuSeatGlobal *sHaikuSeat = NULL; 27 | 28 | 29 | uint32_t FromHaikuKeyCode(uint32 haikuKey) 30 | { 31 | uint32_t wlKey; 32 | switch (haikuKey) { 33 | case 0x01: wlKey = KEY_ESC; break; 34 | case 0x02: wlKey = KEY_F1; break; 35 | case 0x03: wlKey = KEY_F2; break; 36 | case 0x04: wlKey = KEY_F3; break; 37 | case 0x05: wlKey = KEY_F4; break; 38 | case 0x06: wlKey = KEY_F5; break; 39 | case 0x07: wlKey = KEY_F6; break; 40 | case 0x08: wlKey = KEY_F7; break; 41 | case 0x09: wlKey = KEY_F8; break; 42 | case 0x0a: wlKey = KEY_F9; break; 43 | case 0x0b: wlKey = KEY_F10; break; 44 | case 0x0c: wlKey = KEY_F11; break; 45 | case 0x0d: wlKey = KEY_F12; break; 46 | case 0x0e: wlKey = KEY_SYSRQ; break; 47 | case 0x0f: wlKey = KEY_SCROLLLOCK; break; 48 | case 0x10: wlKey = KEY_PAUSE; break; 49 | case 0x11: wlKey = KEY_GRAVE; break; 50 | case 0x12: wlKey = KEY_1; break; 51 | case 0x13: wlKey = KEY_2; break; 52 | case 0x14: wlKey = KEY_3; break; 53 | case 0x15: wlKey = KEY_4; break; 54 | case 0x16: wlKey = KEY_5; break; 55 | case 0x17: wlKey = KEY_6; break; 56 | case 0x18: wlKey = KEY_7; break; 57 | case 0x19: wlKey = KEY_8; break; 58 | case 0x1a: wlKey = KEY_9; break; 59 | case 0x1b: wlKey = KEY_0; break; 60 | case 0x1c: wlKey = KEY_MINUS; break; 61 | case 0x1d: wlKey = KEY_EQUAL; break; 62 | case 0x1e: wlKey = KEY_BACKSPACE; break; 63 | case 0x1f: wlKey = KEY_INSERT; break; 64 | case 0x20: wlKey = KEY_HOME; break; 65 | case 0x21: wlKey = KEY_PAGEUP; break; 66 | case 0x22: wlKey = KEY_NUMLOCK; break; 67 | case 0x23: wlKey = KEY_KPSLASH; break; 68 | case 0x24: wlKey = KEY_KPASTERISK; break; 69 | case 0x25: wlKey = KEY_KPMINUS; break; 70 | case 0x26: wlKey = KEY_TAB; break; 71 | case 0x27: wlKey = KEY_Q; break; 72 | case 0x28: wlKey = KEY_W; break; 73 | case 0x29: wlKey = KEY_E; break; 74 | case 0x2a: wlKey = KEY_R; break; 75 | case 0x2b: wlKey = KEY_T; break; 76 | case 0x2c: wlKey = KEY_Y; break; 77 | case 0x2d: wlKey = KEY_U; break; 78 | case 0x2e: wlKey = KEY_I; break; 79 | case 0x2f: wlKey = KEY_O; break; 80 | case 0x30: wlKey = KEY_P; break; 81 | case 0x31: wlKey = KEY_LEFTBRACE; break; 82 | case 0x32: wlKey = KEY_RIGHTBRACE; break; 83 | case 0x33: wlKey = KEY_BACKSLASH; break; 84 | case 0x34: wlKey = KEY_DELETE; break; 85 | case 0x35: wlKey = KEY_END; break; 86 | case 0x36: wlKey = KEY_PAGEDOWN; break; 87 | case 0x37: wlKey = KEY_KP7; break; 88 | case 0x38: wlKey = KEY_KP8; break; 89 | case 0x39: wlKey = KEY_KP9; break; 90 | case 0x3a: wlKey = KEY_KPPLUS; break; 91 | case 0x3b: wlKey = KEY_CAPSLOCK; break; 92 | case 0x3c: wlKey = KEY_A; break; 93 | case 0x3d: wlKey = KEY_S; break; 94 | case 0x3e: wlKey = KEY_D; break; 95 | case 0x3f: wlKey = KEY_F; break; 96 | case 0x40: wlKey = KEY_G; break; 97 | case 0x41: wlKey = KEY_H; break; 98 | case 0x42: wlKey = KEY_J; break; 99 | case 0x43: wlKey = KEY_K; break; 100 | case 0x44: wlKey = KEY_L; break; 101 | case 0x45: wlKey = KEY_SEMICOLON; break; 102 | case 0x46: wlKey = KEY_APOSTROPHE; break; 103 | case 0x47: wlKey = KEY_ENTER; break; 104 | case 0x48: wlKey = KEY_KP4; break; 105 | case 0x49: wlKey = KEY_KP5; break; 106 | case 0x4a: wlKey = KEY_KP6; break; 107 | case 0x4b: wlKey = KEY_LEFTSHIFT; break; 108 | case 0x4c: wlKey = KEY_Z; break; 109 | case 0x4d: wlKey = KEY_X; break; 110 | case 0x4e: wlKey = KEY_C; break; 111 | case 0x4f: wlKey = KEY_V; break; 112 | case 0x50: wlKey = KEY_B; break; 113 | case 0x51: wlKey = KEY_N; break; 114 | case 0x52: wlKey = KEY_M; break; 115 | case 0x53: wlKey = KEY_COMMA; break; 116 | case 0x54: wlKey = KEY_DOT; break; 117 | case 0x55: wlKey = KEY_SLASH; break; 118 | case 0x56: wlKey = KEY_RIGHTSHIFT; break; 119 | case 0x57: wlKey = KEY_UP; break; 120 | case 0x58: wlKey = KEY_KP1; break; 121 | case 0x59: wlKey = KEY_KP2; break; 122 | case 0x5a: wlKey = KEY_KP3; break; 123 | case 0x5b: wlKey = KEY_KPENTER; break; 124 | case 0x5c: wlKey = KEY_LEFTCTRL; break; 125 | case 0x5d: wlKey = KEY_LEFTALT; break; 126 | case 0x5e: wlKey = KEY_SPACE; break; 127 | case 0x5f: wlKey = KEY_RIGHTALT; break; 128 | case 0x60: wlKey = KEY_RIGHTCTRL; break; 129 | case 0x61: wlKey = KEY_LEFT; break; 130 | case 0x62: wlKey = KEY_DOWN; break; 131 | case 0x63: wlKey = KEY_RIGHT; break; 132 | case 0x64: wlKey = KEY_KP0; break; 133 | case 0x65: wlKey = KEY_KPDOT; break; 134 | case 0x66: wlKey = KEY_LEFTMETA; break; 135 | case 0x67: wlKey = KEY_RIGHTMETA; break; 136 | case 0x68: wlKey = KEY_COMPOSE; break; 137 | case 0x69: wlKey = KEY_102ND; break; 138 | case 0x6a: wlKey = KEY_YEN; break; 139 | case 0x6b: wlKey = KEY_RO; break; 140 | 141 | default: 142 | //fprintf(stderr, "[!] unknown key: %#x\n", haikuKey); 143 | wlKey = 0; 144 | } 145 | return wlKey; 146 | } 147 | 148 | static uint32_t FromHaikuMouseBtnCode(uint32 haikuBtn) 149 | { 150 | uint32_t wlBtn; 151 | switch (haikuBtn) { 152 | case 0: wlBtn = BTN_LEFT; break; 153 | case 1: wlBtn = BTN_RIGHT; break; 154 | case 2: wlBtn = BTN_MIDDLE; break; 155 | case 3: wlBtn = BTN_FORWARD; break; 156 | case 4: wlBtn = BTN_BACK; break; 157 | default: wlBtn = 0; 158 | } 159 | return wlBtn; 160 | } 161 | 162 | static uint32_t FromHaikuModifiers(uint32 haikuModifiers) 163 | { 164 | uint32_t wlModifiers = 0; 165 | if (B_SHIFT_KEY & haikuModifiers) wlModifiers |= (1 << 0); 166 | if (B_COMMAND_KEY & haikuModifiers) wlModifiers |= (1 << 2); 167 | if (B_CONTROL_KEY & haikuModifiers) wlModifiers |= (1 << 3) | (1 << 18); 168 | if (B_CAPS_LOCK & haikuModifiers) wlModifiers |= (1 << 1); 169 | if (B_NUM_LOCK & haikuModifiers) wlModifiers |= (1 << 4); 170 | return wlModifiers; 171 | } 172 | 173 | class SurfaceCursorHook: public HaikuSurface::Hook { 174 | public: 175 | BPoint fHotspot; 176 | void HandleCommit() final; 177 | }; 178 | 179 | void SurfaceCursorHook::HandleCommit() 180 | { 181 | BBitmap *bitmap = Base()->Bitmap(); 182 | if (bitmap != NULL) { 183 | BCursor cursor(bitmap, fHotspot); 184 | AppKitPtrs::LockedPtr(be_app)->SetCursor(&cursor); 185 | } else { 186 | be_app->SetCursor(B_CURSOR_SYSTEM_DEFAULT, true); 187 | } 188 | } 189 | 190 | 191 | //#pragma mark - HaikuPointer 192 | 193 | HaikuPointer::~HaikuPointer() 194 | { 195 | fGlobal->fPointerIfaces.Remove(this); 196 | } 197 | 198 | void HaikuPointer::HandleSetCursor(uint32_t serial, struct wl_resource *_surface, int32_t hotspot_x, int32_t hotspot_y) 199 | { 200 | HaikuSurface *surface = HaikuSurface::FromResource(_surface); 201 | if (surface != NULL) { 202 | SurfaceCursorHook *hook = new SurfaceCursorHook(); 203 | hook->fHotspot = BPoint(hotspot_x, hotspot_y); 204 | surface->SetHook(hook); 205 | } 206 | } 207 | 208 | HaikuKeyboard::~HaikuKeyboard() 209 | { 210 | fGlobal->fKeyboardIfaces.Remove(this); 211 | } 212 | 213 | 214 | //#pragma mark - HaikuSeat 215 | 216 | HaikuSeatGlobal *HaikuSeatGlobal::Create(struct wl_display *display) 217 | { 218 | ObjectDeleter global(new(std::nothrow) HaikuSeatGlobal()); 219 | if (!global.IsSet()) return NULL; 220 | if (!global->Init(display, &wl_seat_interface, SEAT_VERSION)) return NULL; 221 | sHaikuSeat = global.Get(); 222 | return global.Detach(); 223 | } 224 | 225 | void HaikuSeatGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 226 | { 227 | HaikuSeat *seat = new(std::nothrow) HaikuSeat(this); 228 | if (seat == NULL) { 229 | wl_client_post_no_memory(wl_client); 230 | return; 231 | } 232 | if (!seat->Init(wl_client, version, id)) { 233 | return; 234 | } 235 | seat->SendCapabilities(WlSeat::capabilityPointer | WlSeat::capabilityKeyboard); 236 | } 237 | 238 | 239 | uint32_t HaikuSeatGlobal::NextSerial() 240 | { 241 | return (uint32_t)atomic_add((int32*)&fSerial, 1); 242 | } 243 | 244 | void HaikuSeatGlobal::SetPointerFocus(HaikuSurface *surface, const BMessage &msg, TrackId trackId) 245 | { 246 | if (surface == NULL) trackId = trackNone; 247 | if (fPointerFocus == surface && fTrack.id == trackId) { 248 | return; 249 | } 250 | if (fPointerFocus != NULL) { 251 | switch (fTrack.id) { 252 | case trackClient: 253 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 254 | if (pointer->Client() != fPointerFocus->Client()) continue; 255 | pointer->SendLeave(NextSerial(), fPointerFocus->ToResource()); 256 | pointer->SendFrame(); 257 | } 258 | break; 259 | case trackDrag: 260 | fDataDevice->SendLeave(); 261 | break; 262 | } 263 | } 264 | if (surface == NULL) { 265 | fTrack.captured = false; 266 | fTrack.inside = false; 267 | } 268 | if (fPointerFocus != surface) { 269 | if (surface == NULL || msg.FindInt32("buttons", (int32*)&fOldMouseBtns) < B_OK) fOldMouseBtns = 0; 270 | } 271 | fPointerFocus = surface; 272 | fTrack.id = trackId; 273 | if (fPointerFocus != NULL) { 274 | BPoint where; 275 | if (msg.WasDropped()) { 276 | where = msg.DropPoint(); 277 | AppKitPtrs::LockedPtr(fPointerFocus->View())->ConvertFromScreen(&where); 278 | } else if (msg.FindPoint("be:view_where", &where) < B_OK) where = B_ORIGIN; 279 | switch (fTrack.id) { 280 | case trackClient: 281 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 282 | if (pointer->Client() != surface->Client()) continue; 283 | pointer->SendEnter(NextSerial(), surface->ToResource(), wl_fixed_from_double(where.x), wl_fixed_from_double(where.y)); 284 | pointer->SendFrame(); 285 | } 286 | break; 287 | case trackDrag: { 288 | BMessage data; 289 | msg.FindMessage("be:drag_message", &data); 290 | HaikuDataOffer *dataOffer = HaikuDataOffer::Create(fDataDevice, data); 291 | fDataDevice->SendEnter(NextSerial(), fPointerFocus->ToResource(), wl_fixed_from_double(where.x), wl_fixed_from_double(where.y), dataOffer->ToResource()); 292 | break; 293 | } 294 | } 295 | } 296 | } 297 | 298 | void HaikuSeatGlobal::SetPointerFocus(HaikuSurface *surface, bool setFocus, const BMessage &msg, TrackId trackId) 299 | { 300 | if (setFocus) { 301 | SetPointerFocus(surface, msg, trackId); 302 | } else if (fPointerFocus == surface) { 303 | SetPointerFocus(NULL, msg, trackId); 304 | } 305 | } 306 | 307 | void HaikuSeatGlobal::SetKeyboardFocus(HaikuSurface *surface, bool setFocus) 308 | { 309 | if (setFocus) { 310 | if (fKeyboardFocus != surface) { 311 | if (fKeyboardFocus != NULL) { 312 | if (fTextInput != NULL) { 313 | fTextInput->Leave(fKeyboardFocus); 314 | } 315 | for (HaikuKeyboard *keyboard = fKeyboardIfaces.First(); keyboard != NULL; keyboard = fKeyboardIfaces.GetNext(keyboard)) { 316 | if (keyboard->Client() != fKeyboardFocus->Client()) continue; 317 | keyboard->SendLeave(NextSerial(), fKeyboardFocus->ToResource()); 318 | } 319 | } 320 | fKeyboardFocus = surface; 321 | struct wl_array keys{}; 322 | for (HaikuKeyboard *keyboard = fKeyboardIfaces.First(); keyboard != NULL; keyboard = fKeyboardIfaces.GetNext(keyboard)) { 323 | if (keyboard->Client() != surface->Client()) continue; 324 | keyboard->SendEnter(NextSerial(), surface->ToResource(), &keys); 325 | } 326 | if (fTextInput != NULL) { 327 | fTextInput->Enter(surface); 328 | } 329 | } 330 | } else if (fKeyboardFocus == surface) { 331 | if (fTextInput != NULL) { 332 | fTextInput->Leave(surface); 333 | } 334 | for (HaikuKeyboard *keyboard = fKeyboardIfaces.First(); keyboard != NULL; keyboard = fKeyboardIfaces.GetNext(keyboard)) { 335 | if (keyboard->Client() != fKeyboardFocus->Client()) continue; 336 | keyboard->SendLeave(NextSerial(), fKeyboardFocus->ToResource()); 337 | } 338 | fKeyboardFocus = NULL; 339 | } 340 | } 341 | 342 | void HaikuSeatGlobal::DoTrack(TrackId id, const TrackInfo &info) 343 | { 344 | if (fTrack.id != trackClient || fOldMouseBtns == 0 || fPointerFocus == NULL) return; 345 | SetPointerFocus(fPointerFocus, BMessage(), id); 346 | fTrack.info = info; 347 | switch (id) { 348 | case trackResize: { 349 | auto geometry = fPointerFocus->XdgSurface()->Geometry(); 350 | fTrack.wndWidth = geometry.width; 351 | fTrack.wndHeight = geometry.height; 352 | break; 353 | } 354 | } 355 | } 356 | 357 | bool HaikuSeatGlobal::MessageReceived(HaikuSurface *surface, BMessage *msg) 358 | { 359 | if (msg->WasDropped()) { 360 | fprintf(stderr, "WasDropped, (fPointerFocus == surface: %d, fTrack.id == trackDrag: %d)\n", fPointerFocus == surface, fTrack.id == trackDrag); 361 | if (fPointerFocus == surface && fTrack.id == trackDrag) { 362 | fDataDevice->SendDrop(); 363 | fTrack.captured = false; 364 | SetPointerFocus(surface, true, *msg, trackClient); 365 | } 366 | return true; 367 | } 368 | 369 | if (msg->what == B_MOUSE_MOVED) { 370 | int32 transit; 371 | msg->FindInt32("be:transit", &transit); 372 | 373 | if (!fTrack.captured) { 374 | switch (transit) { 375 | case B_ENTERED_VIEW: 376 | case B_INSIDE_VIEW: { 377 | BPoint where; 378 | msg->FindPoint("be:view_where", &where); 379 | bool isDrag = msg->HasMessage("be:drag_message"); 380 | SetPointerFocus(surface, true, *msg, isDrag ? trackDrag : trackClient); 381 | fTrack.captured = isDrag; 382 | break; 383 | } 384 | case B_EXITED_VIEW: 385 | SetPointerFocus(surface, false, BMessage()); 386 | break; 387 | } 388 | } 389 | if (fPointerFocus == surface) { 390 | switch (transit) { 391 | case B_ENTERED_VIEW: 392 | case B_INSIDE_VIEW: 393 | fTrack.inside = true; 394 | break; 395 | case B_EXITED_VIEW: 396 | case B_OUTSIDE_VIEW: 397 | fTrack.inside = false; 398 | if (fTrack.id == trackDrag) { 399 | fTrack.captured = false; 400 | SetPointerFocus(surface, false, BMessage()); 401 | } 402 | break; 403 | } 404 | } 405 | } 406 | 407 | switch (msg->what) { 408 | case B_KEY_DOWN: 409 | case B_KEY_UP: 410 | case B_UNMAPPED_KEY_DOWN: 411 | case B_UNMAPPED_KEY_UP: { 412 | if (fKeyboardFocus != surface) return false; 413 | int32 key; 414 | msg->FindInt32("key", &key); 415 | uint32_t state = (msg->what == B_KEY_UP || msg->what == B_UNMAPPED_KEY_UP) ? WlKeyboard::keyStateReleased : WlKeyboard::keyStatePressed; 416 | 417 | uint32_t wlKey = FromHaikuKeyCode(key); 418 | for (HaikuKeyboard *keyboard = fKeyboardIfaces.First(); keyboard != NULL; keyboard = fKeyboardIfaces.GetNext(keyboard)) { 419 | if (keyboard->Client() != fKeyboardFocus->Client()) continue; 420 | keyboard->SendKey(NextSerial(), system_time()/1000, wlKey, state); 421 | } 422 | return true; 423 | } 424 | case B_MODIFIERS_CHANGED: { 425 | if (fKeyboardFocus != surface) return false; 426 | uint32 modifiers; 427 | if (msg->FindInt32("modifiers", (int32*)&modifiers) < B_OK) modifiers = 0; 428 | for (HaikuKeyboard *keyboard = fKeyboardIfaces.First(); keyboard != NULL; keyboard = fKeyboardIfaces.GetNext(keyboard)) { 429 | if (keyboard->Client() != fKeyboardFocus->Client()) continue; 430 | keyboard->SendModifiers(NextSerial(), FromHaikuModifiers(modifiers), 0, 0, 0); 431 | } 432 | return true; 433 | } 434 | case B_MOUSE_WHEEL_CHANGED: { 435 | if (fPointerFocus != surface) return false; 436 | bigtime_t when; 437 | float dx, dy; 438 | if (msg->FindInt64("when", &when) < B_OK) when = system_time(); 439 | if (msg->FindFloat("be:wheel_delta_x", &dx) < B_OK) dx = 0; 440 | if (msg->FindFloat("be:wheel_delta_y", &dy) < B_OK) dy = 0; 441 | if (dx != 0) { 442 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 443 | if (pointer->Client() != fPointerFocus->Client()) continue; 444 | pointer->SendAxisSource(WlPointer::axisSourceWheel); 445 | pointer->SendAxis(when/1000, WlPointer::axisHorizontalScroll, wl_fixed_from_double(dx*10.0)); 446 | pointer->SendAxisDiscrete(WlPointer::axisHorizontalScroll, dx); 447 | } 448 | } 449 | if (dy != 0) { 450 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 451 | if (pointer->Client() != fPointerFocus->Client()) continue; 452 | pointer->SendAxisSource(WlPointer::axisSourceWheel); 453 | pointer->SendAxis(when/1000, WlPointer::axisVerticalScroll, wl_fixed_from_double(dy*10.0)); 454 | pointer->SendAxisDiscrete(WlPointer::axisVerticalScroll, dy); 455 | } 456 | } 457 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 458 | if (pointer->Client() != fPointerFocus->Client()) continue; 459 | pointer->SendFrame(); 460 | } 461 | return true; 462 | } 463 | case B_MOUSE_DOWN: { 464 | if (fPointerFocus != surface) return false; 465 | bigtime_t when; 466 | BPoint where; 467 | uint32 btns; 468 | msg->FindInt64("when", &when); 469 | msg->FindPoint("be:view_where", &where); 470 | msg->FindInt32("buttons", (int32*)&btns); 471 | uint32 oldBtns = fOldMouseBtns; 472 | if (oldBtns == 0 && btns != 0) { 473 | fTrack.captured = true; 474 | fTrack.origin = where; 475 | AppKitPtrs::LockedPtr(surface->View())->SetMouseEventMask(B_POINTER_EVENTS); 476 | } 477 | fOldMouseBtns = btns; 478 | switch (fTrack.id) { 479 | case trackNone: 480 | case trackClient: { 481 | uint32 btnsDown = btns & (~oldBtns); 482 | for (uint32 i = 0; i < 32; i++) { 483 | if (((1 << i) & btnsDown) != 0) { 484 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 485 | if (pointer->Client() != fPointerFocus->Client()) continue; 486 | pointer->SendButton(NextSerial(), when/1000, FromHaikuMouseBtnCode(i), WlPointer::buttonStatePressed); 487 | } 488 | } 489 | } 490 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 491 | if (pointer->Client() != fPointerFocus->Client()) continue; 492 | pointer->SendFrame(); 493 | } 494 | break; 495 | } 496 | } 497 | return true; 498 | } 499 | case B_MOUSE_UP: { 500 | if (fPointerFocus != surface) return false; 501 | bigtime_t when; 502 | uint32 btns; 503 | msg->FindInt64("when", &when); 504 | msg->FindInt32("buttons", (int32*)&btns); 505 | uint32 oldBtns = fOldMouseBtns; 506 | switch (fTrack.id) { 507 | case trackNone: 508 | case trackClient: { 509 | uint32 btnsUp = oldBtns & (~btns); 510 | for (uint32 i = 0; i < 32; i++) { 511 | if (((1 << i) & btnsUp) != 0) { 512 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 513 | if (pointer->Client() != fPointerFocus->Client()) continue; 514 | pointer->SendButton(NextSerial(), when/1000, FromHaikuMouseBtnCode(i), WlPointer::buttonStateReleased); 515 | } 516 | } 517 | } 518 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 519 | if (pointer->Client() != fPointerFocus->Client()) continue; 520 | pointer->SendFrame(); 521 | } 522 | break; 523 | } 524 | } 525 | if (oldBtns != 0 && btns == 0 && fTrack.id != trackDrag) { 526 | fTrack.captured = false; 527 | } 528 | if (!fTrack.captured) { 529 | SetPointerFocus(surface, fTrack.inside, *msg); 530 | } 531 | fOldMouseBtns = btns; 532 | return true; 533 | } 534 | case B_MOUSE_MOVED: { 535 | if (fPointerFocus != surface) return false; 536 | bigtime_t when; 537 | BPoint where; 538 | uint32 btns; 539 | msg->FindInt64("when", &when); 540 | msg->FindPoint("be:view_where", &where); 541 | switch (fTrack.id) { 542 | case trackNone: 543 | case trackClient: { 544 | for (HaikuPointer *pointer = fPointerIfaces.First(); pointer != NULL; pointer = fPointerIfaces.GetNext(pointer)) { 545 | if (pointer->Client() != fPointerFocus->Client()) continue; 546 | pointer->SendMotion(when / 1000, wl_fixed_from_double(where.x), wl_fixed_from_double(where.y)); 547 | pointer->SendFrame(); 548 | } 549 | break; 550 | } 551 | case trackDrag: { 552 | fDataDevice->SendMotion(when / 1000, wl_fixed_from_double(where.x), wl_fixed_from_double(where.y)); 553 | break; 554 | } 555 | case trackMove: { 556 | fPointerFocus->View()->Window()->MoveBy(where.x - fTrack.origin.x, where.y - fTrack.origin.y); 557 | break; 558 | } 559 | case trackResize: { 560 | switch (fTrack.info.resizeEdge) { 561 | case XdgToplevel::resizeEdgeTopLeft: { 562 | HaikuXdgSurface *xdgSurface = fPointerFocus->XdgSurface(); 563 | HaikuXdgSurface::GeometryInfo oldGeometry = xdgSurface->Geometry(); 564 | if (!xdgSurface->SetConfigurePending()) true; 565 | 566 | fPointerFocus->View()->Window()->MoveBy(where.x - fTrack.origin.x, where.y - fTrack.origin.y); 567 | struct wl_array array{}; 568 | xdgSurface->Toplevel()->SendConfigure(fTrack.wndWidth - (where.x - fTrack.origin.x), fTrack.wndHeight - (where.y - fTrack.origin.y), &array); 569 | fTrack.wndWidth -= where.x - fTrack.origin.x; 570 | fTrack.wndHeight -= where.y - fTrack.origin.y; 571 | xdgSurface->SendConfigure(xdgSurface->NextSerial()); 572 | break; 573 | } 574 | case XdgToplevel::resizeEdgeBottomRight: { 575 | HaikuXdgSurface *xdgSurface = fPointerFocus->XdgSurface(); 576 | HaikuXdgSurface::GeometryInfo oldGeometry = xdgSurface->Geometry(); 577 | if (!xdgSurface->SetConfigurePending()) true; 578 | 579 | int32_t minWidth, minHeight; 580 | int32_t maxWidth, maxHeight; 581 | xdgSurface->Toplevel()->MinSize(minWidth, minHeight); 582 | xdgSurface->Toplevel()->MaxSize(maxWidth, maxHeight); 583 | if (maxWidth == 0) maxWidth = INT32_MAX; 584 | if (maxHeight == 0) maxHeight = INT32_MAX; 585 | int32_t newWidth = std::min(std::max(fTrack.wndWidth + (where.x - fTrack.origin.x), minWidth), maxWidth); 586 | int32_t newHeight = std::min(std::max(fTrack.wndHeight + (where.y - fTrack.origin.y), minHeight), maxHeight); 587 | struct wl_array array{}; 588 | xdgSurface->Toplevel()->SendConfigure(newWidth, newHeight, &array); 589 | xdgSurface->SendConfigure(xdgSurface->NextSerial()); 590 | } 591 | } 592 | break; 593 | } 594 | } 595 | return true; 596 | } 597 | } 598 | if (fTextInput != NULL && fTextInput->MessageReceived(surface, msg)) { 599 | return true; 600 | } 601 | return false; 602 | } 603 | 604 | void HaikuSeatGlobal::UpdateKeymap() 605 | { 606 | int fd; 607 | if (ProduceXkbKeymap(fd) < B_OK) { 608 | fprintf(stderr, "[!] ProduceXkbKeymap failed\n"); 609 | return; 610 | } 611 | FileDescriptorCloser fdCloser(fd); 612 | struct stat st{}; 613 | fstat(fd, &st); 614 | for (HaikuKeyboard *keyboard = fKeyboardIfaces.First(); keyboard != NULL; keyboard = fKeyboardIfaces.GetNext(keyboard)) { 615 | keyboard->SendKeymap(WlKeyboard::keymapFormatXkbV1, fd, st.st_size); 616 | } 617 | } 618 | 619 | 620 | void HaikuSeat::HandleGetPointer(uint32_t id) 621 | { 622 | HaikuPointer *pointer = new(std::nothrow) HaikuPointer(fGlobal); 623 | if (pointer == NULL) { 624 | wl_client_post_no_memory(Client()); 625 | return; 626 | } 627 | if (!pointer->Init(Client(), Version(), id)) { 628 | return; 629 | } 630 | fGlobal->fPointerIfaces.Insert(pointer); 631 | } 632 | 633 | void HaikuSeat::HandleGetKeyboard(uint32_t id) 634 | { 635 | HaikuKeyboard *keyboard = new(std::nothrow) HaikuKeyboard(fGlobal); 636 | if (keyboard == NULL) { 637 | wl_client_post_no_memory(Client()); 638 | return; 639 | } 640 | if (!keyboard->Init(Client(), Version(), id)) { 641 | return; 642 | } 643 | fGlobal->fKeyboardIfaces.Insert(keyboard); 644 | 645 | fGlobal->UpdateKeymap(); 646 | } 647 | 648 | void HaikuSeat::HandleGetTouch(uint32_t id) 649 | { 650 | abort(); 651 | } 652 | 653 | 654 | HaikuSeatGlobal *HaikuGetSeat(struct wl_client *wl_client) 655 | { 656 | return sHaikuSeat; 657 | } 658 | -------------------------------------------------------------------------------- /HaikuSeat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Wayland.h" 3 | #include "WlGlobal.h" 4 | #include "XdgShell.h" 5 | #include "HaikuTextInput.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | class BMessage; 13 | class HaikuSurface; 14 | class HaikuSeatGlobal; 15 | class HaikuDataDevice; 16 | 17 | class HaikuPointer: public WlPointer { 18 | private: 19 | HaikuSeatGlobal *fGlobal; 20 | DoublyLinkedListLink fLink; 21 | 22 | protected: 23 | virtual ~HaikuPointer(); 24 | 25 | public: 26 | typedef DoublyLinkedList> List; 27 | 28 | HaikuPointer(HaikuSeatGlobal *global): fGlobal(global) {} 29 | HaikuSeatGlobal *GetGlobal() const {return fGlobal;} 30 | 31 | void HandleSetCursor(uint32_t serial, struct wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) final; 32 | }; 33 | 34 | class HaikuKeyboard: public WlKeyboard { 35 | private: 36 | HaikuSeatGlobal *fGlobal; 37 | DoublyLinkedListLink fLink; 38 | 39 | protected: 40 | virtual ~HaikuKeyboard(); 41 | 42 | public: 43 | typedef DoublyLinkedList> List; 44 | 45 | HaikuKeyboard(HaikuSeatGlobal *global): fGlobal(global) {} 46 | HaikuSeatGlobal *GetGlobal() const {return fGlobal;} 47 | }; 48 | 49 | class HaikuSeatGlobal: public WlGlocal { 50 | public: 51 | enum TrackId { 52 | trackNone, 53 | trackClient, 54 | trackMove, 55 | trackResize, 56 | trackDrag, 57 | }; 58 | union TrackInfo { 59 | XdgToplevel::ResizeEdge resizeEdge; 60 | }; 61 | private: 62 | friend class HaikuSeat; 63 | friend class HaikuPointer; 64 | friend class HaikuKeyboard; 65 | friend class HaikuDataDevice; 66 | friend class HaikuTextInputGlobal; 67 | friend class HaikuTextInput; 68 | 69 | struct Track { 70 | TrackId id = trackNone; 71 | bool captured; 72 | bool inside; 73 | BPoint origin; 74 | int32_t wndWidth, wndHeight; 75 | TrackInfo info; 76 | }; 77 | 78 | uint32_t fSerial = 1; 79 | HaikuPointer::List fPointerIfaces{}; 80 | HaikuKeyboard::List fKeyboardIfaces{}; 81 | HaikuTextInputGlobal *fTextInput{}; 82 | HaikuDataDevice *fDataDevice{}; 83 | HaikuSurface *fPointerFocus{}; 84 | HaikuSurface *fKeyboardFocus{}; 85 | uint32 fOldMouseBtns{}; 86 | Track fTrack; 87 | 88 | uint32_t NextSerial(); 89 | 90 | public: 91 | static HaikuSeatGlobal *Create(struct wl_display *display); 92 | virtual ~HaikuSeatGlobal() = default; 93 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) override; 94 | 95 | void SetPointerFocus(HaikuSurface *surface, const BMessage &msg, TrackId trackId); 96 | void SetPointerFocus(HaikuSurface *surface, bool setFocus, const BMessage &msg, TrackId trackId = trackClient); 97 | void SetKeyboardFocus(HaikuSurface *surface, bool setFocus); 98 | void DoTrack(TrackId id, const TrackInfo &info = {}); 99 | bool MessageReceived(HaikuSurface *surface, BMessage *msg); 100 | void UpdateKeymap(); 101 | }; 102 | 103 | class HaikuSeat: public WlSeat { 104 | private: 105 | HaikuSeatGlobal *fGlobal; 106 | 107 | protected: 108 | virtual ~HaikuSeat() = default; 109 | 110 | public: 111 | HaikuSeat(HaikuSeatGlobal *global): fGlobal(global) {} 112 | HaikuSeatGlobal *GetGlobal() const {return fGlobal;} 113 | static HaikuSeat *FromResource(struct wl_resource *resource) {return (HaikuSeat*)WlResource::FromResource(resource);} 114 | 115 | void HandleGetPointer(uint32_t id) final; 116 | void HandleGetKeyboard(uint32_t id) final; 117 | void HandleGetTouch(uint32_t id) final; 118 | }; 119 | 120 | 121 | HaikuSeatGlobal *HaikuGetSeat(struct wl_client *wl_client); 122 | -------------------------------------------------------------------------------- /HaikuServerDecoration.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuServerDecoration.h" 2 | #include "HaikuCompositor.h" 3 | #include "HaikuXdgSurface.h" 4 | #include "HaikuXdgToplevel.h" 5 | 6 | #include 7 | 8 | extern const struct wl_interface org_kde_kwin_server_decoration_manager_interface; 9 | 10 | 11 | enum { 12 | SERVER_DECORATION_VERSION = 1, 13 | }; 14 | 15 | 16 | //#pragma mark - HaikuServerDecorationManager 17 | 18 | class HaikuServerDecorationManager: public OrgKdeKwinServerDecorationManager { 19 | protected: 20 | virtual ~HaikuServerDecorationManager() = default; 21 | 22 | public: 23 | void HandleCreate(uint32_t id, struct wl_resource *surface) final; 24 | }; 25 | 26 | 27 | HaikuServerDecorationManagerGlobal *HaikuServerDecorationManagerGlobal::Create(struct wl_display *display) 28 | { 29 | ObjectDeleter global(new(std::nothrow) HaikuServerDecorationManagerGlobal()); 30 | if (!global.IsSet()) return NULL; 31 | if (!global->Init(display, &org_kde_kwin_server_decoration_manager_interface, SERVER_DECORATION_VERSION)) return NULL; 32 | return global.Detach(); 33 | } 34 | 35 | void HaikuServerDecorationManagerGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 36 | { 37 | HaikuServerDecorationManager *manager = new(std::nothrow) HaikuServerDecorationManager(); 38 | if (manager == NULL) { 39 | wl_client_post_no_memory(wl_client); 40 | return; 41 | } 42 | if (!manager->Init(wl_client, version, id)) { 43 | return; 44 | } 45 | manager->SendDefaultMode(OrgKdeKwinServerDecorationManager::modeServer); 46 | } 47 | 48 | 49 | void HaikuServerDecorationManager::HandleCreate(uint32_t id, struct wl_resource *surface_resource) 50 | { 51 | HaikuSurface *surface = HaikuSurface::FromResource(surface_resource); 52 | HaikuServerDecoration::Create(this, surface, id); 53 | } 54 | 55 | 56 | //#pragma mark - HaikuServerDecoration 57 | 58 | HaikuServerDecoration *HaikuServerDecoration::Create(HaikuServerDecorationManager *manager, struct HaikuSurface *surface, uint32_t id) 59 | { 60 | HaikuServerDecoration *serverDecor = new(std::nothrow) HaikuServerDecoration(); 61 | if (!serverDecor) { 62 | wl_client_post_no_memory(manager->Client()); 63 | return NULL; 64 | } 65 | if (!serverDecor->Init(manager->Client(), manager->Version(), id)) { 66 | return NULL; 67 | } 68 | serverDecor->fSurface = surface; 69 | surface->fServerDecoration = serverDecor; 70 | 71 | return serverDecor; 72 | } 73 | 74 | window_look HaikuServerDecoration::Look() 75 | { 76 | switch (fMode) { 77 | case OrgKdeKwinServerDecorationManager::modeClient: 78 | default: 79 | return B_NO_BORDER_WINDOW_LOOK; 80 | case OrgKdeKwinServerDecorationManager::modeServer: 81 | return B_TITLED_WINDOW_LOOK; 82 | } 83 | } 84 | 85 | void HaikuServerDecoration::HandleRequestMode(uint32_t mode) 86 | { 87 | fMode = (OrgKdeKwinServerDecoration::Mode)mode; 88 | if (fSurface->XdgSurface() == NULL) return; 89 | BWindow *window = fSurface->XdgSurface()->Window(); 90 | if (window == NULL) return; 91 | window->SetLook(Look()); 92 | } 93 | -------------------------------------------------------------------------------- /HaikuServerDecoration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Wayland.h" 3 | #include "WlGlobal.h" 4 | #include "ServerDecoration.h" 5 | 6 | #include 7 | 8 | 9 | class HaikuSurface; 10 | class HaikuServerDecorationManager; 11 | 12 | class HaikuServerDecorationManagerGlobal: public WlGlocal { 13 | public: 14 | static HaikuServerDecorationManagerGlobal *Create(struct wl_display *display); 15 | virtual ~HaikuServerDecorationManagerGlobal() = default; 16 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) override; 17 | }; 18 | 19 | class HaikuServerDecoration: public OrgKdeKwinServerDecoration { 20 | private: 21 | HaikuSurface *fSurface; 22 | OrgKdeKwinServerDecoration::Mode fMode = OrgKdeKwinServerDecoration::modeNone; 23 | 24 | public: 25 | static HaikuServerDecoration *Create(HaikuServerDecorationManager *manager, HaikuSurface *surface, uint32_t id); 26 | static HaikuServerDecoration *FromResource(struct wl_resource *resource) {return (HaikuServerDecoration*)WlResource::FromResource(resource);} 27 | 28 | inline OrgKdeKwinServerDecoration::Mode Mode() {return fMode;} 29 | window_look Look(); 30 | 31 | void HandleRequestMode(uint32_t mode) final; 32 | }; 33 | -------------------------------------------------------------------------------- /HaikuShm.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuShm.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | extern const struct wl_interface wl_shm_interface; 11 | 12 | 13 | enum { 14 | SHM_VERSION = 1, 15 | }; 16 | 17 | 18 | HaikuShmGlobal *HaikuShmGlobal::Create(struct wl_display *display) 19 | { 20 | ObjectDeleter global(new(std::nothrow) HaikuShmGlobal()); 21 | if (!global.IsSet()) return NULL; 22 | if (!global->Init(display, &wl_shm_interface, SHM_VERSION)) return NULL; 23 | return global.Detach(); 24 | } 25 | 26 | void HaikuShmGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 27 | { 28 | HaikuShm *res = new(std::nothrow) HaikuShm(); 29 | if (res == NULL) { 30 | wl_client_post_no_memory(wl_client); 31 | return; 32 | } 33 | if (!res->Init(wl_client, version, id)) { 34 | return; 35 | } 36 | res->SendFormat(WlShm::formatArgb8888); 37 | res->SendFormat(WlShm::formatXrgb8888); 38 | } 39 | 40 | 41 | void HaikuShm::HandleCreatePool(uint32_t id, int32_t fd, int32_t size) 42 | { 43 | FileDescriptorCloser fdCloser(fd); 44 | HaikuShmPool *pool = new(std::nothrow) HaikuShmPool(); 45 | if (pool == NULL) { 46 | wl_client_post_no_memory(Client()); 47 | return; 48 | } 49 | if (!pool->Init(Client(), Version(), id)) { 50 | return; 51 | } 52 | 53 | pool->fFd.SetTo(fdCloser.Detach()); 54 | pool->Remap(size); 55 | } 56 | 57 | 58 | void HaikuShmPool::HandleCreateBuffer(uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) 59 | { 60 | HaikuShmBuffer *buffer = new(std::nothrow) HaikuShmBuffer(); 61 | if (buffer == NULL) { 62 | wl_client_post_no_memory(Client()); 63 | return; 64 | } 65 | if (!buffer->Init(Client(), Version(), id)) { 66 | return; 67 | } 68 | 69 | color_space colorSpace; 70 | switch (format) { 71 | case WlShm::formatArgb8888: 72 | colorSpace = B_RGBA32; 73 | break; 74 | case WlShm::formatXrgb8888: 75 | colorSpace = B_RGB32; 76 | break; 77 | default: 78 | wl_resource_post_error(ToResource(), HaikuShm::errorInvalidFormat, "unsupported format: %" PRIu32, format); 79 | return; 80 | } 81 | buffer->fAreaRef = fAreaRef; 82 | buffer->fBitmap.emplace(fAreaRef->Area(), offset, BRect(0, 0, width - 1, height - 1), 0, colorSpace, stride); 83 | if (buffer->fBitmap.value().InitCheck() < B_OK) { 84 | wl_resource_post_error(ToResource(), HaikuShm::errorInvalidFormat, "failed to create BBitmap: %s", strerror(buffer->fBitmap.value().InitCheck())); 85 | return; 86 | } 87 | } 88 | 89 | void HaikuShmPool::Remap(int32_t size) 90 | { 91 | #if 0 92 | fAddress = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fFd.Get(), 0); 93 | if (fAddress == MAP_FAILED) { 94 | fArea.SetTo(errno); 95 | } else { 96 | fArea.SetTo(area_for(fAddress)); 97 | set_area_protection(fArea.Get(), B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA); 98 | } 99 | #endif 100 | AreaDeleter area(_kern_map_file( 101 | "wl_shm", 102 | &fAddress, 103 | B_ANY_ADDRESS, 104 | size, 105 | B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA, 106 | REGION_NO_PRIVATE_MAP, 107 | true, 108 | fFd.Get(), 109 | 0 110 | )); 111 | if (!area.IsSet()) { 112 | wl_resource_post_error(ToResource(), HaikuShm::errorInvalidFd, "failed mmap fd %d: %s", fFd.Get(), strerror(area.Get())); 113 | return; 114 | } 115 | fAreaRef.SetTo(new(std::nothrow) HaikuShmAreaRef(area.Get()), true); 116 | if (!fAreaRef.IsSet()) { 117 | wl_client_post_no_memory(Client()); 118 | return; 119 | } 120 | area.Detach(); 121 | fSize = size; 122 | } 123 | 124 | void HaikuShmPool::HandleResize(int32_t size) 125 | { 126 | Remap(size); 127 | } 128 | -------------------------------------------------------------------------------- /HaikuShm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "WlGlobal.h" 6 | #include "Wayland.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | class HaikuShmGlobal: public WlGlocal { 16 | public: 17 | static HaikuShmGlobal *Create(struct wl_display *display); 18 | virtual ~HaikuShmGlobal() = default; 19 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) final; 20 | }; 21 | 22 | class HaikuShm: public WlShm { 23 | public: 24 | virtual ~HaikuShm() = default; 25 | void HandleCreatePool(uint32_t id, int32_t fd, int32_t size) final; 26 | }; 27 | 28 | class HaikuShmAreaRef: public BReferenceable { 29 | private: 30 | AreaDeleter fArea; 31 | 32 | public: 33 | HaikuShmAreaRef(area_id area): fArea(area) {} 34 | area_id Area() const {return fArea.Get();} 35 | }; 36 | 37 | class HaikuShmPool: public WlShmPool { 38 | private: 39 | friend class HaikuShm; 40 | friend class HaikuShmBuffer; 41 | 42 | FileDescriptorCloser fFd; 43 | BReference fAreaRef; 44 | void *fAddress {}; 45 | size_t fSize {}; 46 | 47 | void Remap(int32_t size); 48 | 49 | public: 50 | virtual ~HaikuShmPool() = default; 51 | void HandleCreateBuffer(uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) final; 52 | void HandleResize(int32_t size) final; 53 | }; 54 | 55 | class HaikuShmBuffer: public WlBuffer, public BReferenceable { 56 | private: 57 | friend class HaikuShmPool; 58 | 59 | BReference fAreaRef; 60 | std::optional fBitmap; 61 | 62 | public: 63 | static HaikuShmBuffer *FromResource(struct wl_resource *resource) {return (HaikuShmBuffer*)WlResource::FromResource(resource);} 64 | virtual ~HaikuShmBuffer() = default; 65 | 66 | void HandleDestroy() final {ReleaseReference();} 67 | 68 | void LastReferenceReleased() final {Destroy();} 69 | 70 | inline BBitmap &Bitmap() {return fBitmap.value();} 71 | }; 72 | -------------------------------------------------------------------------------- /HaikuSubcompositor.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuSubcompositor.h" 2 | #include "HaikuCompositor.h" 3 | 4 | #include "AppKitPtrs.h" 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | extern const struct wl_interface wl_subcompositor_interface; 11 | 12 | 13 | #define SUBCOMPOSITOR_VERSION 1 14 | 15 | 16 | //#pragma mark - HaikuSubcompositor 17 | 18 | class HaikuSubcompositor: public WlSubcompositor { 19 | protected: 20 | virtual ~HaikuSubcompositor() = default; 21 | 22 | public: 23 | void HandleGetSubsurface(uint32_t id, struct wl_resource *surface, struct wl_resource *parent) final; 24 | }; 25 | 26 | 27 | HaikuSubcompositorGlobal *HaikuSubcompositorGlobal::Create(struct wl_display *display) 28 | { 29 | ObjectDeleter global(new(std::nothrow) HaikuSubcompositorGlobal()); 30 | if (!global.IsSet()) return NULL; 31 | if (!global->Init(display, &wl_subcompositor_interface, SUBCOMPOSITOR_VERSION)) return NULL; 32 | return global.Detach(); 33 | } 34 | 35 | void HaikuSubcompositorGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 36 | { 37 | HaikuSubcompositor *manager = new(std::nothrow) HaikuSubcompositor(); 38 | if (manager == NULL) { 39 | wl_client_post_no_memory(wl_client); 40 | return; 41 | } 42 | if (!manager->Init(wl_client, version, id)) { 43 | return; 44 | } 45 | } 46 | 47 | 48 | void HaikuSubcompositor::HandleGetSubsurface(uint32_t id, struct wl_resource *surface, struct wl_resource *parent) 49 | { 50 | HaikuSubsurface *subsurface = HaikuSubsurface::Create(Client(), Version(), id, surface, parent); 51 | } 52 | 53 | 54 | //#pragma mark - HaikuSubsurface 55 | 56 | HaikuSubsurface *HaikuSubsurface::Create(struct wl_client *client, uint32_t version, uint32_t id, struct wl_resource *surface, struct wl_resource *parent) 57 | { 58 | HaikuSubsurface *subsurface = new(std::nothrow) HaikuSubsurface(); 59 | if (!subsurface->Init(client, version, id)) { 60 | return NULL; 61 | } 62 | HaikuSurface *haikuSurface = HaikuSurface::FromResource(surface); 63 | subsurface->fSurface = haikuSurface; 64 | haikuSurface->fSubsurface = subsurface; 65 | subsurface->fParent = HaikuSurface::FromResource(parent); 66 | subsurface->fParent->SurfaceList().Insert(subsurface); 67 | 68 | BView *parentView = subsurface->fParent->View(); 69 | if (parentView) { 70 | haikuSurface->AttachView(parentView); 71 | haikuSurface->AttachViewsToEarlierSubsurfaces(); 72 | } 73 | return subsurface; 74 | } 75 | 76 | HaikuSubsurface::~HaikuSubsurface() 77 | { 78 | fSurface->Detach(); 79 | if (fParent != NULL) { 80 | fParent->SurfaceList().Remove(this); 81 | } 82 | fSurface->fSubsurface = NULL; 83 | } 84 | 85 | 86 | HaikuSurface *HaikuSubsurface::Root() 87 | { 88 | HaikuSurface *s = fParent; 89 | while (s->Subsurface() != NULL) { 90 | s = s->Subsurface()->fParent; 91 | } 92 | return s; 93 | } 94 | 95 | void HaikuSubsurface::GetOffset(int32_t &x, int32 &y) 96 | { 97 | x = fState.x; 98 | y = fState.y; 99 | HaikuSubsurface *s = fParent->Subsurface(); 100 | while (s != NULL) { 101 | x += s->fState.x; 102 | y += s->fState.y; 103 | s = s->fParent->Subsurface(); 104 | } 105 | } 106 | 107 | 108 | void HaikuSubsurface::HandleSetPosition(int32_t x, int32_t y) 109 | { 110 | fState.x = x; 111 | fState.y = y; 112 | } 113 | 114 | void HaikuSubsurface::HandlePlaceAbove(struct wl_resource *sibling) 115 | { 116 | } 117 | 118 | void HaikuSubsurface::HandlePlaceBelow(struct wl_resource *sibling) 119 | { 120 | } 121 | 122 | void HaikuSubsurface::HandleSetSync() 123 | { 124 | } 125 | 126 | void HaikuSubsurface::HandleSetDesync() 127 | { 128 | } 129 | -------------------------------------------------------------------------------- /HaikuSubcompositor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Wayland.h" 4 | #include "WlGlobal.h" 5 | #include 6 | 7 | 8 | class HaikuSurface; 9 | 10 | class HaikuSubcompositorGlobal: public WlGlocal { 11 | public: 12 | static HaikuSubcompositorGlobal *Create(struct wl_display *display); 13 | virtual ~HaikuSubcompositorGlobal() = default; 14 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) override; 15 | }; 16 | 17 | class HaikuSubsurface: public WlSubsurface { 18 | private: 19 | DoublyLinkedListLink fLink; 20 | 21 | public: 22 | typedef DoublyLinkedList> SurfaceList; 23 | 24 | struct State { 25 | int32_t x = 0, y = 0; 26 | }; 27 | 28 | private: 29 | friend class HaikuSurface; 30 | 31 | HaikuSurface *fSurface{}; 32 | HaikuSurface *fParent{}; 33 | State fState; 34 | State fPendingState; 35 | 36 | public: 37 | static HaikuSubsurface *Create(struct wl_client *client, uint32_t version, uint32_t id, struct wl_resource *surface, struct wl_resource *parent); 38 | virtual ~HaikuSubsurface(); 39 | 40 | HaikuSurface *Surface() {return fSurface;} 41 | HaikuSurface *Parent() {return fParent;} 42 | HaikuSurface *Root(); 43 | const State &GetState() {return fState;} 44 | 45 | void GetOffset(int32_t &x, int32 &y); 46 | 47 | void HandleSetPosition(int32_t x, int32_t y) final; 48 | void HandlePlaceAbove(struct wl_resource *sibling) final; 49 | void HandlePlaceBelow(struct wl_resource *sibling) final; 50 | void HandleSetSync() final; 51 | void HandleSetDesync() final; 52 | }; 53 | -------------------------------------------------------------------------------- /HaikuTextInput.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuTextInput.h" 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "AppKitPtrs.h" 12 | #include "HaikuCompositor.h" 13 | #include "HaikuSeat.h" 14 | 15 | 16 | enum { 17 | TEXT_INPUT_VERSION = 1, 18 | }; 19 | 20 | 21 | // #pragma mark - HaikuTextInputGlobal 22 | 23 | HaikuTextInputGlobal *HaikuTextInputGlobal::Create(struct wl_display *display, HaikuSeatGlobal *seat) 24 | { 25 | ObjectDeleter global(new(std::nothrow) HaikuTextInputGlobal(seat)); 26 | if (!global.IsSet()) return NULL; 27 | if (!global->Init(display, &zwp_text_input_manager_v3_interface, TEXT_INPUT_VERSION)) return NULL; 28 | seat->fTextInput = global.Get(); 29 | return global.Detach(); 30 | } 31 | 32 | HaikuTextInputGlobal::~HaikuTextInputGlobal() 33 | { 34 | fSeat->fTextInput = NULL; 35 | } 36 | 37 | void HaikuTextInputGlobal::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 38 | { 39 | //printf("HaikuTextInputGlobal::Bind()\n"); 40 | HaikuTextInputManager *res = new(std::nothrow) HaikuTextInputManager(this); 41 | if (res == NULL) { 42 | wl_client_post_no_memory(wl_client); 43 | return; 44 | } 45 | if (!res->Init(wl_client, version, id)) { 46 | return; 47 | } 48 | } 49 | 50 | void HaikuTextInputGlobal::Clear() 51 | { 52 | fString = ""; 53 | fSelectionBeg = -1; 54 | fSelectionEnd = -1; 55 | fActive = false; 56 | fConfirmed = false; 57 | fImReplyMsgr = BMessenger(); 58 | } 59 | 60 | void HaikuTextInputGlobal::SendState(HaikuTextInput *textInput) 61 | { 62 | if (fActive) { 63 | if (fConfirmed) { 64 | textInput->SendCommitString(fString.String()); 65 | } else { 66 | textInput->SendPreeditString(fString.String(), fSelectionBeg, fSelectionEnd); 67 | } 68 | } 69 | textInput->SendDone(fSerial); 70 | } 71 | 72 | void HaikuTextInputGlobal::Enter(HaikuSurface *surface) 73 | { 74 | for (HaikuTextInput *textInput = fTextInputIfaces.First(); textInput != NULL; textInput = fTextInputIfaces.GetNext(textInput)) { 75 | if (textInput->Client() != surface->Client()) {continue;} 76 | textInput->SendEnter(surface->ToResource()); 77 | } 78 | } 79 | 80 | void HaikuTextInputGlobal::Leave(HaikuSurface *surface) 81 | { 82 | for (HaikuTextInput *textInput = fTextInputIfaces.First(); textInput != NULL; textInput = fTextInputIfaces.GetNext(textInput)) { 83 | if (textInput->Client() != surface->Client()) {continue;} 84 | textInput->SendLeave(surface->ToResource()); 85 | } 86 | } 87 | 88 | bool HaikuTextInputGlobal::MessageReceived(HaikuSurface *surface, BMessage *msg) 89 | { 90 | //printf("HaikuTextInputGlobal::MessageReceived()\n"); 91 | 92 | if (fSeat->fKeyboardFocus != surface) { 93 | return false; 94 | } 95 | switch (msg->what) { 96 | case B_INPUT_METHOD_EVENT: { 97 | int32 opcode {}; 98 | if (msg->FindInt32("be:opcode", &opcode) < B_OK) { 99 | return false; 100 | } 101 | switch (opcode) { 102 | case B_INPUT_METHOD_STARTED: { 103 | //printf("B_INPUT_METHOD_STARTED\n"); 104 | if (msg->FindMessenger("be:reply_to", &fImReplyMsgr) < B_OK) { 105 | Clear(); 106 | return true; 107 | } 108 | fActive = true; 109 | 110 | return true; 111 | } 112 | case B_INPUT_METHOD_STOPPED: { 113 | //printf("B_INPUT_METHOD_STOPPED\n"); 114 | 115 | for (HaikuTextInput *textInput = fTextInputIfaces.First(); textInput != NULL; textInput = fTextInputIfaces.GetNext(textInput)) { 116 | if (textInput->Client() != fSeat->fKeyboardFocus->Client()) continue; 117 | SendState(textInput); 118 | } 119 | Clear(); 120 | return true; 121 | } 122 | case B_INPUT_METHOD_CHANGED: { 123 | //printf("B_INPUT_METHOD_CHANGED\n"); 124 | 125 | if (msg->FindString("be:string", &fString) < B_OK) { 126 | fString = ""; 127 | } 128 | if ( 129 | msg->FindInt32("be:selection", 0, &fSelectionBeg) < B_OK || 130 | msg->FindInt32("be:selection", 1, &fSelectionEnd) < B_OK 131 | ) { 132 | fSelectionBeg = -1; 133 | fSelectionEnd = -1; 134 | } 135 | if (msg->FindBool("be:confirmed", &fConfirmed) < B_OK) { 136 | fConfirmed = false; 137 | } 138 | //printf(" string: \"%s\"\n", fString.String()); 139 | //printf(" selection: %" B_PRId32 ", %" B_PRId32 "\n", fSelectionBeg, fSelectionEnd); 140 | 141 | for (HaikuTextInput *textInput = fTextInputIfaces.First(); textInput != NULL; textInput = fTextInputIfaces.GetNext(textInput)) { 142 | if (textInput->Client() != fSeat->fKeyboardFocus->Client()) continue; 143 | SendState(textInput); 144 | } 145 | if (fConfirmed) { 146 | Clear(); 147 | } 148 | 149 | return true; 150 | }; 151 | case B_INPUT_METHOD_LOCATION_REQUEST: { 152 | //printf("B_INPUT_METHOD_LOCATION_REQUEST\n"); 153 | if (!fImReplyMsgr.IsValid()) { 154 | return true; 155 | } 156 | int32 charCount = UTF8CountChars(fString.String(), fString.Length()); 157 | BPoint location = fCursorRect.LeftTop(); 158 | float height = fCursorRect.Height(); 159 | AppKitPtrs::LockedPtr(surface->View())->ConvertToScreen(&location); 160 | 161 | BMessage reply(B_INPUT_METHOD_EVENT); 162 | reply.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); 163 | for (int32 i = 0; i < charCount; i++) { 164 | reply.AddPoint("be:location_reply", location); 165 | reply.AddFloat("be:height_reply", height); 166 | } 167 | 168 | fImReplyMsgr.SendMessage(&reply); 169 | 170 | return true; 171 | } 172 | } 173 | return false; 174 | } 175 | } 176 | return false; 177 | } 178 | 179 | 180 | // #pragma mark - HaikuTextInputManager 181 | 182 | void HaikuTextInputManager::HandleGetTextInput(uint32_t id, struct wl_resource *seat) 183 | { 184 | HaikuTextInput *res = new(std::nothrow) HaikuTextInput(fGlobal, HaikuSeat::FromResource(seat)->GetGlobal()); 185 | if (res == NULL) { 186 | wl_client_post_no_memory(Client()); 187 | return; 188 | } 189 | if (!res->Init(Client(), Version(), id)) { 190 | return; 191 | } 192 | } 193 | 194 | 195 | // #pragma mark - HaikuTextInput 196 | 197 | HaikuTextInput::HaikuTextInput(HaikuTextInputGlobal *global, HaikuSeatGlobal *seat): 198 | fGlobal(global), 199 | fSeat(seat) 200 | { 201 | fGlobal->fTextInputIfaces.Insert(this); 202 | } 203 | 204 | HaikuTextInput::~HaikuTextInput() 205 | { 206 | fGlobal->fTextInputIfaces.Remove(this); 207 | } 208 | 209 | void HaikuTextInput::HandleEnable() 210 | { 211 | //printf("HaikuTextInput::HandleEnable()\n"); 212 | } 213 | 214 | void HaikuTextInput::HandleDisable() 215 | { 216 | //printf("HaikuTextInput::HandleDisable()\n"); 217 | if (fGlobal->fActive) { 218 | if (fGlobal->fImReplyMsgr.IsValid()) { 219 | BMessage reply(B_INPUT_METHOD_EVENT); 220 | reply.AddInt32("be:opcode", B_INPUT_METHOD_STOPPED); 221 | fGlobal->fImReplyMsgr.SendMessage(&reply); 222 | } 223 | fGlobal->Clear(); 224 | } 225 | } 226 | 227 | void HaikuTextInput::HandleSetSurroundingText(const char *text, int32_t cursor, int32_t anchor) 228 | { 229 | //printf("HaikuTextInput::HandleSetSurroundingText(\"%s\", %" PRId32 ", %" PRId32 ")\n", text, cursor, anchor); 230 | } 231 | 232 | void HaikuTextInput::HandleSetTextChangeCause(uint32_t cause) 233 | { 234 | //printf("HaikuTextInput::HandleSetTextChangeCause(%" PRId32 ")\n", cause); 235 | } 236 | 237 | void HaikuTextInput::HandleSetContentType(uint32_t hint, uint32_t purpose) 238 | { 239 | } 240 | 241 | void HaikuTextInput::HandleSetCursorRectangle(int32_t x, int32_t y, int32_t width, int32_t height) 242 | { 243 | //printf("HaikuTextInput::HandleSetCursorRectangle(%" PRId32 ", %" PRId32 ", %" PRId32 ", %" PRId32 ")\n", x, y, width, height); 244 | fGlobal->fCursorRect = BRect(x, y, x + width - 1, y + height - 1); 245 | } 246 | 247 | void HaikuTextInput::HandleCommit() 248 | { 249 | //printf("HaikuTextInput::HandleCommit()\n"); 250 | fGlobal->fSerial++; 251 | 252 | fGlobal->SendState(this); 253 | } 254 | -------------------------------------------------------------------------------- /HaikuTextInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "WlGlobal.h" 6 | #include "TextInputUnstableV3.h" 7 | #include 8 | #include 9 | 10 | class HaikuSurface; 11 | class HaikuSeatGlobal; 12 | class HaikuTextInputGlobal; 13 | 14 | 15 | class HaikuTextInput: public ZwpTextInputV3 { 16 | private: 17 | HaikuTextInputGlobal *fGlobal; 18 | HaikuSeatGlobal *fSeat; 19 | DoublyLinkedListLink fLink; 20 | 21 | public: 22 | typedef DoublyLinkedList> List; 23 | 24 | public: 25 | HaikuTextInput(HaikuTextInputGlobal *global, HaikuSeatGlobal *seat); 26 | virtual ~HaikuTextInput(); 27 | 28 | void HandleEnable() final; 29 | void HandleDisable() final; 30 | void HandleSetSurroundingText(const char *text, int32_t cursor, int32_t anchor) final; 31 | void HandleSetTextChangeCause(uint32_t cause) final; 32 | void HandleSetContentType(uint32_t hint, uint32_t purpose) final; 33 | void HandleSetCursorRectangle(int32_t x, int32_t y, int32_t width, int32_t height) final; 34 | void HandleCommit() final; 35 | }; 36 | 37 | 38 | class HaikuTextInputGlobal: public WlGlocal { 39 | private: 40 | friend class HaikuTextInput; 41 | 42 | HaikuSeatGlobal *fSeat; 43 | HaikuTextInput::List fTextInputIfaces{}; 44 | 45 | int32 fSerial {}; 46 | 47 | BMessenger fImReplyMsgr; 48 | BString fString; 49 | int32 fSelectionBeg {}; 50 | int32 fSelectionEnd {}; 51 | bool fActive {}; 52 | bool fConfirmed {}; 53 | 54 | BRect fCursorRect; 55 | 56 | HaikuTextInputGlobal(HaikuSeatGlobal *seat): fSeat(seat) {} 57 | 58 | void Clear(); 59 | void SendState(HaikuTextInput *textInput); 60 | 61 | public: 62 | static HaikuTextInputGlobal *Create(struct wl_display *display, HaikuSeatGlobal *seat); 63 | virtual ~HaikuTextInputGlobal(); 64 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) final; 65 | 66 | void Enter(HaikuSurface *surface); 67 | void Leave(HaikuSurface *surface); 68 | 69 | bool MessageReceived(HaikuSurface *surface, BMessage *msg); 70 | }; 71 | 72 | 73 | class HaikuTextInputManager: public ZwpTextInputManagerV3 { 74 | private: 75 | HaikuTextInputGlobal *fGlobal; 76 | 77 | public: 78 | virtual ~HaikuTextInputManager() = default; 79 | HaikuTextInputManager(HaikuTextInputGlobal *global): fGlobal(global) {} 80 | 81 | void HandleGetTextInput(uint32_t id, struct wl_resource *seat) final; 82 | }; 83 | 84 | 85 | -------------------------------------------------------------------------------- /HaikuXdgPopup.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuXdgPopup.h" 2 | #include "HaikuXdgSurface.h" 3 | #include "HaikuXdgPositioner.h" 4 | #include "WaylandEnv.h" 5 | 6 | #include "AppKitPtrs.h" 7 | 8 | #include 9 | #include 10 | 11 | 12 | class WaylandPopupWindow: public BWindow { 13 | private: 14 | friend class HaikuXdgPopup; 15 | HaikuXdgPopup *fPopup; 16 | 17 | public: 18 | WaylandPopupWindow(HaikuXdgPopup *popup, BRect frame, const char* title, window_look look, window_feel feel, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE); 19 | virtual ~WaylandPopupWindow() = default; 20 | 21 | HaikuXdgPopup *Popup() {return fPopup;} 22 | 23 | bool QuitRequested() final; 24 | void DispatchMessage(BMessage *msg, BHandler *target) final; 25 | }; 26 | 27 | WaylandPopupWindow::WaylandPopupWindow(HaikuXdgPopup *popup, BRect frame, const char* title, window_look look, window_feel feel, uint32 flags, uint32 workspace): 28 | BWindow(frame, title, look, feel, flags, workspace), 29 | fPopup(popup) 30 | { 31 | } 32 | 33 | bool WaylandPopupWindow::QuitRequested() 34 | { 35 | WaylandEnv vlEnv(this); 36 | if (fPopup != NULL) 37 | fPopup->SendPopupDone(); 38 | return true; 39 | } 40 | 41 | void WaylandPopupWindow::DispatchMessage(BMessage *msg, BHandler *target) 42 | { 43 | switch (msg->what) { 44 | case B_KEY_DOWN: 45 | case B_UNMAPPED_KEY_DOWN: 46 | // Do not use built-in shortcut handling. 47 | target->MessageReceived(msg); 48 | return; 49 | } 50 | BWindow::DispatchMessage(msg, target); 51 | } 52 | 53 | 54 | void HaikuXdgPopup::UpdatePosition(struct wl_resource *_positioner) 55 | { 56 | HaikuXdgPositioner *positioner = HaikuXdgPositioner::FromResource(_positioner); 57 | 58 | BRect workArea = BScreen(fParent->Window()).Frame(); 59 | fParent->ConvertFromScreen(workArea); 60 | 61 | positioner->GetPosition(fPosition, workArea); 62 | } 63 | 64 | HaikuXdgPopup *HaikuXdgPopup::Create(HaikuXdgSurface *xdgSurface, uint32_t id, struct wl_resource *_parent, struct wl_resource *_positioner) 65 | { 66 | HaikuXdgPopup *xdgPopup = new(std::nothrow) HaikuXdgPopup(); 67 | if (!xdgPopup) { 68 | wl_client_post_no_memory(xdgSurface->Client()); 69 | return NULL; 70 | } 71 | if (!xdgPopup->Init(xdgSurface->Client(), xdgSurface->Version(), id)) { 72 | return NULL; 73 | } 74 | 75 | xdgPopup->fXdgSurface = xdgSurface; 76 | xdgPopup->fParent = HaikuXdgSurface::FromResource(_parent); 77 | xdgPopup->fXdgSurface->fRoot = xdgPopup->fParent->fRoot; 78 | 79 | xdgPopup->UpdatePosition(_positioner); 80 | 81 | xdgPopup->fWindow = new WaylandPopupWindow(xdgPopup, BRect(), "", B_NO_BORDER_WINDOW_LOOK, B_FLOATING_SUBSET_WINDOW_FEEL, B_AVOID_FOCUS); 82 | xdgSurface->Surface()->AttachWindow(xdgPopup->fWindow); 83 | xdgSurface->Surface()->AttachViewsToEarlierSubsurfaces(); 84 | xdgPopup->fWindow->AddToSubset(xdgPopup->fXdgSurface->fRoot->Window()); 85 | 86 | return xdgPopup; 87 | } 88 | 89 | HaikuXdgPopup::~HaikuXdgPopup() 90 | { 91 | fXdgSurface->Surface()->Detach(); 92 | 93 | if (fWindow != NULL) { 94 | fWindow->fPopup = NULL; 95 | fWindow->PostMessage(B_QUIT_REQUESTED); 96 | //fWindow->Lock(); 97 | //fWindow->Quit(); 98 | fWindow = NULL; 99 | } 100 | } 101 | 102 | void HaikuXdgPopup::HandleGrab(struct wl_resource *seat, uint32_t serial) 103 | { 104 | } 105 | 106 | void HaikuXdgPopup::HandleReposition(struct wl_resource *positioner, uint32_t token) 107 | { 108 | UpdatePosition(positioner); 109 | 110 | SendRepositioned(token); 111 | SendConfigure(fPosition.left, fPosition.top, (int32_t)fPosition.Width() + 1, (int32_t)fPosition.Height() + 1); 112 | fXdgSurface->SendConfigure(fXdgSurface->NextSerial()); 113 | } 114 | -------------------------------------------------------------------------------- /HaikuXdgPopup.h: -------------------------------------------------------------------------------- 1 | #include "XdgShell.h" 2 | #include 3 | 4 | 5 | struct HaikuXdgSurface; 6 | class BWindow; 7 | class WaylandPopupWindow; 8 | 9 | class HaikuXdgPopup: public XdgPopup { 10 | private: 11 | friend class XdgSurfaceHook; 12 | HaikuXdgSurface *fXdgSurface{}; 13 | HaikuXdgSurface *fParent{}; 14 | WaylandPopupWindow *fWindow{}; 15 | BRect fPosition; 16 | 17 | void UpdatePosition(struct wl_resource *_positioner); 18 | 19 | public: 20 | static HaikuXdgPopup *Create(HaikuXdgSurface *xdg_surface, uint32_t id, struct wl_resource *parent, struct wl_resource *positioner); 21 | virtual ~HaikuXdgPopup(); 22 | 23 | HaikuXdgSurface *XdgSurface() {return fXdgSurface;} 24 | BWindow *Window() {return (BWindow*)fWindow;} 25 | 26 | void HandleGrab(struct wl_resource *seat, uint32_t serial) final; 27 | void HandleReposition(struct wl_resource *positioner, uint32_t token) final; 28 | }; 29 | -------------------------------------------------------------------------------- /HaikuXdgPositioner.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuXdgPositioner.h" 2 | #include "HaikuXdgShell.h" 3 | 4 | #include 5 | #include 6 | 7 | 8 | static void GetPosition(const HaikuXdgPositioner::State &state, BRect &pos) 9 | { 10 | pos = BRect( 11 | BPoint(state.offset.x, state.offset.y), 12 | BSize(state.size.width - 1, state.size.height - 1) 13 | ); 14 | 15 | switch (state.anchor) { 16 | case XdgPositioner::anchorTop: 17 | case XdgPositioner::anchorTopLeft: 18 | case XdgPositioner::anchorTopRight: 19 | pos.OffsetBy(0, state.anchorRect.y); 20 | break; 21 | case XdgPositioner::anchorBottom: 22 | case XdgPositioner::anchorBottomLeft: 23 | case XdgPositioner::anchorBottomRight: 24 | pos.OffsetBy(0, state.anchorRect.y + state.anchorRect.height); 25 | break; 26 | default: 27 | pos.OffsetBy(0, state.anchorRect.y + state.anchorRect.height/2); 28 | break; 29 | } 30 | 31 | switch (state.anchor) { 32 | case XdgPositioner::anchorLeft: 33 | case XdgPositioner::anchorTopLeft: 34 | case XdgPositioner::anchorBottomLeft: 35 | pos.OffsetBy(state.anchorRect.x, 0); 36 | break; 37 | case XdgPositioner::anchorRight: 38 | case XdgPositioner::anchorTopRight: 39 | case XdgPositioner::anchorBottomRight: 40 | pos.OffsetBy(state.anchorRect.x + state.anchorRect.width, 0); 41 | break; 42 | default: 43 | pos.OffsetBy(state.anchorRect.x + state.anchorRect.width/2, 0); 44 | break; 45 | } 46 | 47 | switch (state.gravity) { 48 | case XdgPositioner::gravityTop: 49 | case XdgPositioner::gravityTopLeft: 50 | case XdgPositioner::gravityTopRight: 51 | pos.OffsetBy(0, -(pos.Height() + 1)); 52 | break; 53 | case XdgPositioner::gravityBottom: 54 | case XdgPositioner::gravityBottomLeft: 55 | case XdgPositioner::gravityBottomRight: 56 | break; 57 | default: 58 | pos.OffsetBy(0, -(((int32)pos.Height() + 1) / 2)); 59 | break; 60 | } 61 | 62 | switch (state.gravity) { 63 | case XdgPositioner::gravityLeft: 64 | case XdgPositioner::gravityTopLeft: 65 | case XdgPositioner::gravityBottomLeft: 66 | pos.OffsetBy(-(pos.Width() + 1), 0); 67 | break; 68 | case XdgPositioner::gravityRight: 69 | case XdgPositioner::gravityTopRight: 70 | case XdgPositioner::gravityBottomRight: 71 | break; 72 | default: 73 | pos.OffsetBy(-(((int32)pos.Width() + 1) / 2), 0); 74 | break; 75 | } 76 | } 77 | 78 | static void GetConstrainedOffsets(BRect &offsets, const BRect &pos, const BRect &workArea) 79 | { 80 | offsets.left = workArea.left - pos.left; 81 | offsets.top = workArea.top - pos.top; 82 | offsets.right = -workArea.right + pos.right; 83 | offsets.bottom = -workArea.bottom + pos.bottom; 84 | } 85 | 86 | static bool IsUnconstrained(const BRect &offsets) 87 | { 88 | return 89 | offsets.left <= 0 && 90 | offsets.top <= 0 && 91 | offsets.right <= 0 && 92 | offsets.bottom <= 0; 93 | } 94 | 95 | static bool UnconstrainByFlip(const HaikuXdgPositioner::State &state, BRect &pos, BRect &offsets, const BRect &workArea) 96 | { 97 | bool flipX = ((offsets.left > 0) ^ (offsets.right > 0)) && (state.constraintAdjustment & XdgPositioner::constraintAdjustmentFlipX); 98 | bool flipY = ((offsets.top > 0) ^ (offsets.bottom > 0)) && (state.constraintAdjustment & XdgPositioner::constraintAdjustmentFlipY); 99 | 100 | if (!flipX && !flipY) 101 | return false; 102 | 103 | HaikuXdgPositioner::State flipped = state; 104 | if (flipX) { 105 | switch (flipped.anchor) { 106 | case XdgPositioner::anchorLeft: flipped.anchor = XdgPositioner::anchorRight; break; 107 | case XdgPositioner::anchorRight: flipped.anchor = XdgPositioner::anchorLeft; break; 108 | case XdgPositioner::anchorTopLeft: flipped.anchor = XdgPositioner::anchorTopRight; break; 109 | case XdgPositioner::anchorBottomLeft: flipped.anchor = XdgPositioner::anchorBottomRight; break; 110 | case XdgPositioner::anchorTopRight: flipped.anchor = XdgPositioner::anchorTopLeft; break; 111 | case XdgPositioner::anchorBottomRight: flipped.anchor = XdgPositioner::anchorBottomLeft; break; 112 | default: break; 113 | } 114 | switch (flipped.gravity) { 115 | case XdgPositioner::gravityLeft: flipped.gravity = XdgPositioner::gravityRight; break; 116 | case XdgPositioner::gravityRight: flipped.gravity = XdgPositioner::gravityLeft; break; 117 | case XdgPositioner::gravityTopLeft: flipped.gravity = XdgPositioner::gravityTopRight; break; 118 | case XdgPositioner::gravityBottomLeft: flipped.gravity = XdgPositioner::gravityBottomRight; break; 119 | case XdgPositioner::gravityTopRight: flipped.gravity = XdgPositioner::gravityTopLeft; break; 120 | case XdgPositioner::gravityBottomRight: flipped.gravity = XdgPositioner::gravityBottomLeft; break; 121 | default: break; 122 | } 123 | } 124 | if (flipY) { 125 | switch (flipped.anchor) { 126 | case XdgPositioner::anchorTop: flipped.anchor = XdgPositioner::anchorBottom; break; 127 | case XdgPositioner::anchorBottom: flipped.anchor = XdgPositioner::anchorTop; break; 128 | case XdgPositioner::anchorTopLeft: flipped.anchor = XdgPositioner::anchorBottomLeft; break; 129 | case XdgPositioner::anchorBottomLeft: flipped.anchor = XdgPositioner::anchorTopLeft; break; 130 | case XdgPositioner::anchorTopRight: flipped.anchor = XdgPositioner::anchorBottomRight; break; 131 | case XdgPositioner::anchorBottomRight: flipped.anchor = XdgPositioner::anchorTopRight; break; 132 | default: break; 133 | } 134 | switch (flipped.gravity) { 135 | case XdgPositioner::gravityTop: flipped.gravity = XdgPositioner::gravityBottom; break; 136 | case XdgPositioner::gravityBottom: flipped.gravity = XdgPositioner::gravityTop; break; 137 | case XdgPositioner::gravityTopLeft: flipped.gravity = XdgPositioner::gravityBottomLeft; break; 138 | case XdgPositioner::gravityBottomLeft: flipped.gravity = XdgPositioner::gravityTopLeft; break; 139 | case XdgPositioner::gravityTopRight: flipped.gravity = XdgPositioner::gravityBottomRight; break; 140 | case XdgPositioner::gravityBottomRight: flipped.gravity = XdgPositioner::gravityTopRight; break; 141 | default: break; 142 | } 143 | } 144 | 145 | BRect flippedPos; 146 | BRect flippedOffsets; 147 | GetPosition(flipped, flippedPos); 148 | GetConstrainedOffsets(flippedOffsets, flippedPos, workArea); 149 | 150 | if (flippedOffsets.left <= 0 && flippedOffsets.right <= 0) { 151 | pos.left = flippedPos.left; 152 | pos.right = flippedPos.right; 153 | offsets.left = flippedOffsets.left; 154 | offsets.right = flippedOffsets.right; 155 | } 156 | if (flippedOffsets.top <= 0 && flippedOffsets.bottom <= 0) { 157 | pos.top = flippedPos.top; 158 | pos.bottom = flippedPos.bottom; 159 | offsets.top = flippedOffsets.top; 160 | offsets.bottom = flippedOffsets.bottom; 161 | } 162 | 163 | return IsUnconstrained(offsets); 164 | } 165 | 166 | static bool UnconstrainBySlide(const HaikuXdgPositioner::State &state, BRect &pos, BRect &offsets, const BRect &workArea) 167 | { 168 | bool slideX = (offsets.left > 0 || offsets.right > 0) && (state.constraintAdjustment & XdgPositioner::constraintAdjustmentSlideX); 169 | bool slideY = (offsets.top > 0 || offsets.bottom > 0) && (state.constraintAdjustment & XdgPositioner::constraintAdjustmentSlideY); 170 | 171 | if (!slideX && !slideY) 172 | return false; 173 | 174 | if (slideX) { 175 | if (offsets.left > 0 && offsets.right > 0) { 176 | switch (state.gravity) { 177 | case XdgPositioner::gravityLeft: 178 | case XdgPositioner::gravityTopLeft: 179 | case XdgPositioner::gravityBottomLeft: 180 | pos.OffsetBy(-offsets.right, 0); 181 | break; 182 | default: 183 | pos.OffsetBy(offsets.left, 0); 184 | break; 185 | } 186 | } else { 187 | if (std::abs(offsets.left) < std::abs(offsets.right)) { 188 | pos.OffsetBy(offsets.left, 0); 189 | } else { 190 | pos.OffsetBy(-offsets.right, 0); 191 | } 192 | } 193 | } 194 | 195 | if (slideY) { 196 | if (offsets.top > 0 && offsets.bottom > 0) { 197 | switch (state.gravity) { 198 | case XdgPositioner::gravityTop: 199 | case XdgPositioner::gravityTopLeft: 200 | case XdgPositioner::gravityTopRight: 201 | pos.OffsetBy(0, -offsets.bottom); 202 | break; 203 | default: 204 | pos.OffsetBy(0, offsets.top); 205 | break; 206 | } 207 | } else { 208 | if (std::abs(offsets.top) < std::abs(offsets.bottom)) { 209 | pos.OffsetBy(0, offsets.top); 210 | } else { 211 | pos.OffsetBy(0, -offsets.bottom); 212 | } 213 | } 214 | } 215 | 216 | GetConstrainedOffsets(offsets, pos, workArea); 217 | return IsUnconstrained(offsets); 218 | } 219 | 220 | static bool UnconstrainByResize(const HaikuXdgPositioner::State &state, BRect &pos, BRect &offsets, const BRect &workArea) 221 | { 222 | bool resizeX = (offsets.left > 0 || offsets.right > 0) && (state.constraintAdjustment & XdgPositioner::constraintAdjustmentResizeX); 223 | bool resizeY = (offsets.top > 0 || offsets.bottom > 0) && (state.constraintAdjustment & XdgPositioner::constraintAdjustmentResizeY); 224 | 225 | if (!resizeX && !resizeY) 226 | return false; 227 | 228 | if (offsets.left < 0) offsets.left = 0; 229 | if (offsets.right < 0) offsets.right = 0; 230 | if (offsets.top < 0) offsets.top = 0; 231 | if (offsets.bottom < 0) offsets.bottom = 0; 232 | 233 | BRect resizedPos = pos; 234 | if (resizeX) { 235 | resizedPos.OffsetBy(offsets.left, 0); 236 | resizedPos.right -= offsets.left + offsets.right; 237 | } 238 | if (resizeY) { 239 | resizedPos.OffsetBy(0, offsets.top); 240 | resizedPos.bottom -= offsets.top + offsets.bottom; 241 | } 242 | 243 | if (!resizedPos.IsValid()) 244 | return false; 245 | 246 | GetConstrainedOffsets(offsets, pos, workArea); 247 | return IsUnconstrained(offsets); 248 | } 249 | 250 | static void UnconstrainPosition(const HaikuXdgPositioner::State &state, BRect &pos, const BRect &workArea) 251 | { 252 | BRect offsets; 253 | GetConstrainedOffsets(offsets, pos, workArea); 254 | if (IsUnconstrained(offsets)) return; 255 | if (UnconstrainByFlip (state, pos, offsets, workArea)) return; 256 | if (UnconstrainBySlide (state, pos, offsets, workArea)) return; 257 | if (UnconstrainByResize(state, pos, offsets, workArea)) return; 258 | } 259 | 260 | 261 | //#pragma mark - HaikuXdgPositioner 262 | 263 | HaikuXdgPositioner *HaikuXdgPositioner::Create(HaikuXdgWmBase *client, uint32_t id) 264 | { 265 | HaikuXdgPositioner *positioner = new(std::nothrow) HaikuXdgPositioner(); 266 | if (positioner == NULL) { 267 | wl_client_post_no_memory(client->Client()); 268 | return NULL; 269 | } 270 | if (!positioner->Init(client->Client(), client->Version(), id)) { 271 | return NULL; 272 | } 273 | return positioner; 274 | } 275 | 276 | 277 | void HaikuXdgPositioner::GetPosition(BRect &pos, const BRect &workArea) 278 | { 279 | ::GetPosition(fState, pos); 280 | UnconstrainPosition(fState, pos, workArea); 281 | } 282 | 283 | 284 | void HaikuXdgPositioner::HandleSetSize(int32_t width, int32_t height) 285 | { 286 | fState.valid.size = true; 287 | fState.size = {width, height}; 288 | } 289 | 290 | void HaikuXdgPositioner::HandleSetAnchorRect(int32_t x, int32_t y, int32_t width, int32_t height) 291 | { 292 | fState.valid.anchorRect = true; 293 | fState.anchorRect = {x, y, width, height}; 294 | } 295 | 296 | void HaikuXdgPositioner::HandleSetAnchor(uint32_t anchor) 297 | { 298 | fState.valid.anchor = true; 299 | fState.anchor = anchor; 300 | } 301 | 302 | void HaikuXdgPositioner::HandleSetGravity(uint32_t gravity) 303 | { 304 | fState.valid.gravity = true; 305 | fState.gravity = gravity; 306 | } 307 | 308 | void HaikuXdgPositioner::HandleSetConstraintAdjustment(uint32_t constraint_adjustment) 309 | { 310 | fState.valid.constraintAdjustment = true; 311 | fState.constraintAdjustment = constraint_adjustment; 312 | } 313 | 314 | void HaikuXdgPositioner::HandleSetOffset(int32_t x, int32_t y) 315 | { 316 | fState.valid.offset = true; 317 | fState.offset = {x, y}; 318 | } 319 | 320 | void HaikuXdgPositioner::HandleSetReactive() 321 | { 322 | fState.valid.reactive = true; 323 | } 324 | 325 | void HaikuXdgPositioner::HandleSetParentSize(int32_t parent_width, int32_t parent_height) 326 | { 327 | fState.valid.parentSize = true; 328 | fState.parentSize = {parent_width, parent_height}; 329 | } 330 | 331 | void HaikuXdgPositioner::HandleSetParentConfigure(uint32_t serial) 332 | { 333 | fState.valid.parentConfigure = true; 334 | fState.parentConfigure = {serial}; 335 | } 336 | -------------------------------------------------------------------------------- /HaikuXdgPositioner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XdgShell.h" 3 | #include 4 | 5 | 6 | class HaikuXdgWmBase; 7 | 8 | class HaikuXdgPositioner: public XdgPositioner { 9 | public: 10 | union Valid { 11 | struct { 12 | uint32_t size: 1; 13 | uint32_t anchorRect: 1; 14 | uint32_t anchor: 1; 15 | uint32_t gravity: 1; 16 | uint32_t constraintAdjustment: 1; 17 | uint32_t offset: 1; 18 | uint32_t reactive: 1; 19 | uint32_t parentSize: 1; 20 | uint32_t parentConfigure: 1; 21 | }; 22 | uint32_t val; 23 | }; 24 | 25 | struct State { 26 | Valid valid{}; 27 | struct { 28 | int32_t width; 29 | int32_t height; 30 | } size; 31 | struct { 32 | int32_t x; 33 | int32_t y; 34 | int32_t width; 35 | int32_t height; 36 | } anchorRect; 37 | uint32_t anchor; 38 | uint32_t gravity; 39 | uint32_t constraintAdjustment; 40 | struct { 41 | int32_t x; 42 | int32_t y; 43 | } offset; 44 | struct { 45 | int32_t width; 46 | int32_t height; 47 | } parentSize; 48 | struct { 49 | uint32_t serial; 50 | } parentConfigure; 51 | }; 52 | private: 53 | State fState{}; 54 | 55 | public: 56 | static HaikuXdgPositioner *Create(HaikuXdgWmBase *client, uint32_t id); 57 | static HaikuXdgPositioner *FromResource(struct wl_resource *resource) {return (HaikuXdgPositioner*)WlResource::FromResource(resource);} 58 | 59 | const State &GetState() const {return fState;} 60 | void GetPosition(BRect &pos, const BRect &workArea); 61 | 62 | void HandleSetSize(int32_t width, int32_t height) final; 63 | void HandleSetAnchorRect(int32_t x, int32_t y, int32_t width, int32_t height) final; 64 | void HandleSetAnchor(uint32_t anchor) final; 65 | void HandleSetGravity(uint32_t gravity) final; 66 | void HandleSetConstraintAdjustment(uint32_t constraint_adjustment) final; 67 | void HandleSetOffset(int32_t x, int32_t y) final; 68 | void HandleSetReactive() final; 69 | void HandleSetParentSize(int32_t parent_width, int32_t parent_height) final; 70 | void HandleSetParentConfigure(uint32_t serial) final; 71 | }; 72 | -------------------------------------------------------------------------------- /HaikuXdgShell.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuXdgShell.h" 2 | #include "HaikuXdgSurface.h" 3 | #include "HaikuXdgPositioner.h" 4 | #include "HaikuCompositor.h" 5 | #include "Wayland.h" 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #define WM_BASE_VERSION 3 13 | 14 | static void Assert(bool cond) {if (!cond) abort();} 15 | 16 | 17 | //#pragma mark - xdg_base 18 | 19 | 20 | HaikuXdgShell *HaikuXdgShell::Create(struct wl_display *display) 21 | { 22 | ObjectDeleter global(new(std::nothrow) HaikuXdgShell()); 23 | if (!global.IsSet()) return NULL; 24 | if (!global->Init(display, &xdg_wm_base_interface, WM_BASE_VERSION)) return NULL; 25 | return global.Detach(); 26 | } 27 | 28 | void HaikuXdgShell::Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) 29 | { 30 | HaikuXdgWmBase *client = new(std::nothrow) HaikuXdgWmBase(this); 31 | if (client == NULL) { 32 | wl_client_post_no_memory(wl_client); 33 | return; 34 | } 35 | if (!client->Init(wl_client, version, id)) { 36 | return; 37 | } 38 | 39 | fClients.Insert(client); 40 | } 41 | 42 | 43 | HaikuXdgWmBase::~HaikuXdgWmBase() 44 | { 45 | // TODO: delete owned surfaces 46 | 47 | fShell->fClients.Remove(this); 48 | } 49 | 50 | void HaikuXdgWmBase::HandleCreatePositioner(uint32_t id) 51 | { 52 | HaikuXdgPositioner *positioner = HaikuXdgPositioner::Create(this, id); 53 | } 54 | 55 | void HaikuXdgWmBase::HandleGetXdgSurface(uint32_t id, struct wl_resource *surface_resource) 56 | { 57 | HaikuSurface *surface = HaikuSurface::FromResource(surface_resource); 58 | HaikuXdgSurface::Create(this, surface, id); 59 | } 60 | 61 | void HaikuXdgWmBase::HandlePong(uint32_t serial) 62 | { 63 | } 64 | -------------------------------------------------------------------------------- /HaikuXdgShell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "XdgShell.h" 4 | #include "WlGlobal.h" 5 | #include 6 | 7 | struct HaikuXdgShell; 8 | 9 | 10 | class HaikuXdgWmBase: public XdgWmBase { 11 | private: 12 | HaikuXdgShell *fShell; 13 | DoublyLinkedListLink fLink; 14 | 15 | public: 16 | typedef DoublyLinkedList> List; 17 | 18 | HaikuXdgWmBase(HaikuXdgShell *shell): fShell(shell) {} 19 | virtual ~HaikuXdgWmBase(); 20 | static HaikuXdgWmBase *FromResource(struct wl_resource *resource) {return (HaikuXdgWmBase*)WlResource::FromResource(resource);} 21 | 22 | void HandleCreatePositioner(uint32_t id) override; 23 | void HandleGetXdgSurface(uint32_t id, struct wl_resource *surface) override; 24 | void HandlePong(uint32_t serial) override; 25 | }; 26 | 27 | class HaikuXdgShell: public WlGlocal { 28 | private: 29 | friend class HaikuXdgWmBase; 30 | 31 | HaikuXdgWmBase::List fClients; 32 | 33 | public: 34 | static HaikuXdgShell *Create(struct wl_display *display); 35 | virtual ~HaikuXdgShell() = default; 36 | void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) override; 37 | }; 38 | -------------------------------------------------------------------------------- /HaikuXdgSurface.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuXdgSurface.h" 2 | #include "HaikuXdgShell.h" 3 | #include "HaikuXdgToplevel.h" 4 | #include "HaikuXdgPopup.h" 5 | #include "HaikuCompositor.h" 6 | #include "HaikuServerDecoration.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #include "AppKitPtrs.h" 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | static void Assert(bool cond) {if (!cond) abort();} 19 | 20 | 21 | class XdgSurfaceHook: public HaikuSurface::Hook { 22 | private: 23 | HaikuXdgSurface *fXdgSurface; 24 | public: 25 | XdgSurfaceHook(HaikuXdgSurface *xdgSurface); 26 | void HandleCommit() final; 27 | }; 28 | 29 | XdgSurfaceHook::XdgSurfaceHook(HaikuXdgSurface *xdgSurface): 30 | fXdgSurface(xdgSurface) 31 | {} 32 | 33 | void XdgSurfaceHook::HandleCommit() 34 | { 35 | // TODO: move to HaikuXdgToplevel/HaikuXdgPopup 36 | if (fXdgSurface->HasServerDecoration()) { 37 | // toplevel: window size limits 38 | if (fXdgSurface->fToplevel != NULL && fXdgSurface->fToplevel->fSizeLimitsDirty) { 39 | fXdgSurface->Window()->SetSizeLimits( 40 | fXdgSurface->fToplevel->fMinWidth == 0 ? 0 : fXdgSurface->fToplevel->fMinWidth - 1, 41 | fXdgSurface->fToplevel->fMaxWidth == 0 ? 32768 : fXdgSurface->fToplevel->fMaxWidth - 1, 42 | fXdgSurface->fToplevel->fMinHeight == 0 ? 0 : fXdgSurface->fToplevel->fMinHeight - 1, 43 | fXdgSurface->fToplevel->fMaxHeight == 0 ? 32768 : fXdgSurface->fToplevel->fMaxHeight - 1 44 | ); 45 | if ( 46 | fXdgSurface->fToplevel->fMinWidth != 0 && fXdgSurface->fToplevel->fMinWidth == fXdgSurface->fToplevel->fMaxWidth && 47 | fXdgSurface->fToplevel->fMinHeight != 0 && fXdgSurface->fToplevel->fMinHeight == fXdgSurface->fToplevel->fMaxHeight 48 | ) { 49 | fXdgSurface->Window()->SetFlags(fXdgSurface->Window()->Flags() | B_NOT_RESIZABLE); 50 | } else { 51 | fXdgSurface->Window()->SetFlags(fXdgSurface->Window()->Flags() & ~B_NOT_RESIZABLE); 52 | } 53 | fXdgSurface->fToplevel->fSizeLimitsDirty = false; 54 | } 55 | 56 | if ((int32_t)fXdgSurface->fToplevel->fResizeSerial - (int32_t)(int32_t)fXdgSurface->fAckSerial > 0) { 57 | } else if (!fXdgSurface->fGeometry.Equals(fXdgSurface->fPendingGeometry)) { 58 | BSize oldSize(fXdgSurface->fToplevel->fWidth - 1, fXdgSurface->fToplevel->fHeight - 1); 59 | BSize newSize = oldSize; 60 | 61 | if (fXdgSurface->Surface()->View() != NULL) 62 | AppKitPtrs::LockedPtr(fXdgSurface->Surface()->View())->MoveTo(-fXdgSurface->fPendingGeometry.x, -fXdgSurface->fPendingGeometry.y); 63 | newSize.width = fXdgSurface->fPendingGeometry.width - 1; 64 | newSize.height = fXdgSurface->fPendingGeometry.height - 1; 65 | 66 | if (oldSize != newSize) { 67 | fXdgSurface->fToplevel->fSizeChanged = true; 68 | fXdgSurface->fToplevel->fWidth = (int32_t)newSize.width + 1; 69 | fXdgSurface->fToplevel->fHeight = (int32_t)newSize.height + 1; 70 | 71 | fXdgSurface->Window()->ResizeTo(newSize.width, newSize.height); 72 | } 73 | } 74 | } else { 75 | if ( 76 | fXdgSurface->fPendingGeometry.x != fXdgSurface->fGeometry.x || 77 | fXdgSurface->fPendingGeometry.y != fXdgSurface->fGeometry.y 78 | ) { 79 | fXdgSurface->Window()->MoveBy( 80 | fXdgSurface->fGeometry.x - fXdgSurface->fPendingGeometry.x, 81 | fXdgSurface->fGeometry.y - fXdgSurface->fPendingGeometry.x 82 | ); 83 | } 84 | if (fXdgSurface->Surface()->Bitmap() != NULL) { 85 | BSize oldSize = fXdgSurface->Window()->Size(); 86 | BSize newSize = fXdgSurface->Surface()->Bitmap()->Bounds().Size(); 87 | if (oldSize != newSize) { 88 | fXdgSurface->Window()->ResizeTo(newSize.width, newSize.height); 89 | } 90 | } 91 | } 92 | fXdgSurface->fGeometry = fXdgSurface->fPendingGeometry; 93 | 94 | // initial window show 95 | if (!fXdgSurface->fSurfaceInitalized && fXdgSurface->Surface()->Bitmap() != NULL) { 96 | if (fXdgSurface->Surface()->ServerDecoration() != NULL) { 97 | fXdgSurface->Window()->SetLook(fXdgSurface->Surface()->ServerDecoration()->Look()); 98 | } 99 | if (fXdgSurface->fToplevel != NULL) { 100 | fXdgSurface->Window()->CenterOnScreen(); 101 | } 102 | fXdgSurface->Window()->Show(); 103 | fXdgSurface->fSurfaceInitalized = true; 104 | } 105 | 106 | if (fXdgSurface->fPopup != NULL) { 107 | BRect wndRect = fXdgSurface->fPopup->fPosition; 108 | if (fXdgSurface->Geometry().valid && !fXdgSurface->HasServerDecoration()) 109 | wndRect.OffsetBy(-fXdgSurface->Geometry().x, -fXdgSurface->Geometry().y); 110 | fXdgSurface->fPopup->fParent->ConvertToScreen(wndRect); 111 | fXdgSurface->Window()->MoveTo(wndRect.left, wndRect.top); 112 | } 113 | 114 | // initial configure 115 | if (!fXdgSurface->fConfigureCalled) { 116 | if (fXdgSurface->fToplevel != NULL) { 117 | fXdgSurface->fToplevel->DoSendConfigure(); 118 | } 119 | if (fXdgSurface->fPopup != NULL) { 120 | BRect wndRect = fXdgSurface->fPopup->fPosition; 121 | fXdgSurface->fPopup->SendConfigure(wndRect.left, wndRect.top, (int32_t)wndRect.Width() + 1, (int32_t)wndRect.Height() + 1); 122 | } 123 | fXdgSurface->fConfigureCalled = true; 124 | fXdgSurface->SendConfigure(fXdgSurface->NextSerial()); 125 | } 126 | } 127 | 128 | 129 | //#pragma mark - HaikuXdgSurface 130 | HaikuXdgSurface::~HaikuXdgSurface() 131 | { 132 | fSurface->SetHook(NULL); 133 | } 134 | 135 | 136 | uint32_t HaikuXdgSurface::NextSerial() 137 | { 138 | return (uint32_t)atomic_add((int32*)&fSerial, 1); 139 | } 140 | 141 | BWindow *HaikuXdgSurface::Window() 142 | { 143 | if (fToplevel != NULL) return fToplevel->Window(); 144 | if (fPopup != NULL) return fPopup->Window(); 145 | return NULL; 146 | } 147 | 148 | bool HaikuXdgSurface::HasServerDecoration() 149 | { 150 | return 151 | Geometry().valid && 152 | Surface()->ServerDecoration() != NULL && 153 | Surface()->ServerDecoration()->Mode() == OrgKdeKwinServerDecoration::modeServer; 154 | } 155 | 156 | void HaikuXdgSurface::ConvertFromScreen(BPoint &pt) 157 | { 158 | Window()->ConvertFromScreen(&pt); 159 | if (fGeometry.valid) 160 | pt -= BPoint(fGeometry.x, fGeometry.y); 161 | } 162 | 163 | void HaikuXdgSurface::ConvertToScreen(BPoint &pt) 164 | { 165 | if (fGeometry.valid) 166 | pt += BPoint(fGeometry.x, fGeometry.y); 167 | 168 | Window()->ConvertToScreen(&pt); 169 | } 170 | 171 | void HaikuXdgSurface::ConvertFromScreen(BRect &rect) 172 | { 173 | Window()->ConvertFromScreen(&rect); 174 | if (fGeometry.valid && !HasServerDecoration()) 175 | rect.OffsetBy(-fGeometry.x, -fGeometry.y); 176 | } 177 | 178 | void HaikuXdgSurface::ConvertToScreen(BRect &rect) 179 | { 180 | if (fGeometry.valid && !HasServerDecoration()) 181 | rect.OffsetBy(fGeometry.x, fGeometry.y); 182 | 183 | Window()->ConvertToScreen(&rect); 184 | } 185 | 186 | 187 | void HaikuXdgSurface::HandleGetToplevel(uint32_t id) 188 | { 189 | fToplevel = HaikuXdgToplevel::Create(this, id); 190 | } 191 | 192 | void HaikuXdgSurface::HandleGetPopup(uint32_t id, struct wl_resource *parent, struct wl_resource *positioner) 193 | { 194 | fPopup = HaikuXdgPopup::Create(this, id, parent, positioner); 195 | } 196 | 197 | void HaikuXdgSurface::HandleSetWindowGeometry(int32_t x, int32_t y, int32_t width, int32_t height) 198 | { 199 | fPendingGeometry = { 200 | .valid = true, 201 | .x = x, 202 | .y = y, 203 | .width = width, 204 | .height = height 205 | }; 206 | } 207 | 208 | void HaikuXdgSurface::HandleAckConfigure(uint32_t serial) 209 | { 210 | fAckSerial = serial; 211 | fConfigurePending = false; 212 | } 213 | 214 | 215 | HaikuXdgSurface *HaikuXdgSurface::Create(struct HaikuXdgWmBase *client, struct HaikuSurface *surface, uint32_t id) 216 | { 217 | HaikuXdgSurface *xdgSurface = new(std::nothrow) HaikuXdgSurface(); 218 | if (!xdgSurface) { 219 | wl_client_post_no_memory(client->Client()); 220 | return NULL; 221 | } 222 | if (!xdgSurface->Init(client->Client(), client->Version(), id)) { 223 | return NULL; 224 | } 225 | xdgSurface->fSurface = surface; 226 | xdgSurface->fRoot = xdgSurface; 227 | surface->fXdgSurface = xdgSurface; 228 | surface->SetHook(new XdgSurfaceHook(xdgSurface)); 229 | 230 | return xdgSurface; 231 | } 232 | -------------------------------------------------------------------------------- /HaikuXdgSurface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XdgShell.h" 3 | #include "HaikuCompositor.h" 4 | 5 | class HaikuSurface; 6 | class HaikuXdgWmBase; 7 | class HaikuXdgToplevel; 8 | class HaikuXdgPopup; 9 | 10 | class HaikuXdgSurface: public XdgSurface { 11 | public: 12 | struct GeometryInfo { 13 | bool valid; 14 | int32_t x; 15 | int32_t y; 16 | int32_t width; 17 | int32_t height; 18 | 19 | inline bool Equals(GeometryInfo &other) 20 | { 21 | return 22 | valid == other.valid && 23 | x == other.x && 24 | y == other.y && 25 | width == other.width && 26 | height == other.height; 27 | } 28 | }; 29 | 30 | private: 31 | friend class HaikuXdgToplevel; 32 | friend class HaikuXdgPopup; 33 | friend class HaikuSurface; 34 | friend class XdgSurfaceHook; 35 | 36 | HaikuSurface *fSurface{}; 37 | HaikuXdgToplevel *fToplevel{}; 38 | HaikuXdgPopup *fPopup{}; 39 | HaikuXdgSurface *fRoot{}; 40 | 41 | uint32_t fSerial = 1; 42 | uint32_t fAckSerial = 1; 43 | bool fConfigureCalled = false; 44 | bool fSurfaceInitalized = false; 45 | bool fConfigurePending = false; 46 | GeometryInfo fGeometry{}, fPendingGeometry{}; 47 | 48 | public: 49 | virtual ~HaikuXdgSurface(); 50 | static HaikuXdgSurface *Create(struct HaikuXdgWmBase *client, struct HaikuSurface *surface, uint32_t id); 51 | static HaikuXdgSurface *FromResource(struct wl_resource *resource) {return (HaikuXdgSurface*)WlResource::FromResource(resource);} 52 | 53 | uint32_t NextSerial(); 54 | bool SetConfigurePending() {if (fConfigurePending) return false; else fConfigurePending = true; return true;} 55 | struct GeometryInfo Geometry() {return fGeometry;} 56 | HaikuSurface *Surface() {return fSurface;} 57 | HaikuXdgToplevel *Toplevel() {return fToplevel;} 58 | BWindow *Window(); 59 | bool HasServerDecoration(); 60 | void ConvertFromScreen(BPoint &pt); 61 | void ConvertToScreen(BPoint &pt); 62 | void ConvertFromScreen(BRect &rect); 63 | void ConvertToScreen(BRect &rect); 64 | 65 | void HandleGetToplevel(uint32_t id) override; 66 | void HandleGetPopup(uint32_t id, struct wl_resource *parent, struct wl_resource *positioner) override; 67 | void HandleSetWindowGeometry(int32_t x, int32_t y, int32_t width, int32_t height) override; 68 | void HandleAckConfigure(uint32_t serial) override; 69 | }; 70 | -------------------------------------------------------------------------------- /HaikuXdgToplevel.cpp: -------------------------------------------------------------------------------- 1 | #include "HaikuXdgToplevel.h" 2 | #include "HaikuXdgShell.h" 3 | #include "HaikuXdgSurface.h" 4 | #include "HaikuCompositor.h" 5 | #include "HaikuSeat.h" 6 | #include "HaikuServerDecoration.h" 7 | #include "WaylandEnv.h" 8 | #include 9 | #include 10 | #include 11 | 12 | #include "AppKitPtrs.h" 13 | 14 | #include 15 | #include 16 | 17 | static void Assert(bool cond) {if (!cond) abort();} 18 | 19 | 20 | class WaylandWindow: public BWindow { 21 | private: 22 | friend class HaikuXdgToplevel; 23 | HaikuXdgToplevel *fToplevel; 24 | 25 | public: 26 | WaylandWindow(HaikuXdgToplevel *toplevel, BRect frame, const char* title, window_look look, window_feel feel, uint32 flags, uint32 workspace = B_CURRENT_WORKSPACE); 27 | virtual ~WaylandWindow() = default; 28 | 29 | HaikuXdgToplevel *Toplevel() {return fToplevel;} 30 | 31 | bool QuitRequested() final; 32 | void WindowActivated(bool isActive) final; 33 | void FrameResized(float newWidth, float newHeight) final; 34 | void DispatchMessage(BMessage *msg, BHandler *target) final; 35 | }; 36 | 37 | WaylandWindow::WaylandWindow(HaikuXdgToplevel *toplevel, BRect frame, const char* title, window_look look, window_feel feel, uint32 flags, uint32 workspace): 38 | BWindow(frame, title, look, feel, flags, workspace), 39 | fToplevel(toplevel) 40 | { 41 | } 42 | 43 | bool WaylandWindow::QuitRequested() 44 | { 45 | WaylandEnv vlEnv(this); 46 | if (fToplevel == NULL) 47 | return true; 48 | fToplevel->SendClose(); 49 | return false; 50 | } 51 | 52 | void WaylandWindow::WindowActivated(bool isActive) 53 | { 54 | WaylandEnv vlEnv(this); 55 | if (isActive != fToplevel->fState.activated) { 56 | fToplevel->fState.activated = !fToplevel->fState.activated; 57 | fToplevel->DoSendConfigure(); 58 | fToplevel->XdgSurface()->SendConfigure(fToplevel->XdgSurface()->NextSerial()); 59 | } 60 | } 61 | 62 | void WaylandWindow::FrameResized(float newWidth, float newHeight) 63 | { 64 | WaylandEnv vlEnv(this); 65 | 66 | if (fToplevel->fSizeChanged) { 67 | fToplevel->fSizeChanged = false; 68 | return; 69 | } 70 | 71 | if(!fToplevel->XdgSurface()->HasServerDecoration()) 72 | return; 73 | 74 | if ((int32_t)newWidth + 1 == fToplevel->fWidth && (int32_t)newHeight + 1 == fToplevel->fHeight) 75 | return; 76 | 77 | fToplevel->fWidth = (int32_t)newWidth + 1; 78 | fToplevel->fHeight = (int32_t)newHeight + 1; 79 | 80 | fToplevel->fResizeSerial = fToplevel->XdgSurface()->NextSerial(); 81 | 82 | fToplevel->DoSendConfigure(); 83 | fToplevel->XdgSurface()->SendConfigure(fToplevel->fResizeSerial); 84 | } 85 | 86 | void WaylandWindow::DispatchMessage(BMessage *msg, BHandler *target) 87 | { 88 | switch (msg->what) { 89 | case B_KEY_DOWN: 90 | case B_UNMAPPED_KEY_DOWN: 91 | // Do not use built-in shortcut handling. 92 | target->MessageReceived(msg); 93 | return; 94 | } 95 | BWindow::DispatchMessage(msg, target); 96 | } 97 | 98 | 99 | //#pragma mark - HaikuXdgToplevel 100 | 101 | void HaikuXdgToplevel::DoSendConfigure() 102 | { 103 | uint32_t stateArray[4]; 104 | struct wl_array state { 105 | .size = 0, 106 | .alloc = sizeof(stateArray), 107 | .data = &stateArray[0] 108 | }; 109 | uint32_t *p = (uint32_t*)state.data; 110 | 111 | if (fState.maximized ) {*p++ = XdgToplevel::stateMaximized;} 112 | if (fState.fullscreen) {*p++ = XdgToplevel::stateFullscreen;} 113 | if (fState.resizing ) {*p++ = XdgToplevel::stateResizing;} 114 | if (fState.activated ) {*p++ = XdgToplevel::stateActivated;} 115 | 116 | state.size = (uint8_t*)p - (uint8_t*)state.data; 117 | SendConfigure(fWidth, fHeight, &state); 118 | } 119 | 120 | void HaikuXdgToplevel::HandleSetParent(struct wl_resource *_parent) 121 | { 122 | // TODO: update root window when parent window is closed 123 | HaikuXdgToplevel *parent = HaikuXdgToplevel::FromResource(_parent); 124 | if (parent == NULL) { 125 | if (XdgSurface()->fRoot != XdgSurface()) { 126 | fWindow->RemoveFromSubset(XdgSurface()->fRoot->Window()); 127 | fWindow->SetFeel(B_NORMAL_WINDOW_FEEL); 128 | XdgSurface()->fRoot = XdgSurface(); 129 | } 130 | } else { 131 | XdgSurface()->fRoot = parent->XdgSurface()->fRoot; 132 | fWindow->SetFeel(B_FLOATING_SUBSET_WINDOW_FEEL); 133 | fWindow->AddToSubset(parent->XdgSurface()->fRoot->Window()); 134 | } 135 | } 136 | 137 | void HaikuXdgToplevel::HandleSetTitle(const char *title) 138 | { 139 | fWindow->SetTitle(title); 140 | } 141 | 142 | void HaikuXdgToplevel::HandleSetAppId(const char *app_id) 143 | { 144 | } 145 | 146 | void HaikuXdgToplevel::HandleShowWindowMenu(struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y) 147 | { 148 | } 149 | 150 | void HaikuXdgToplevel::HandleMove(struct wl_resource *_seat, uint32_t serial) 151 | { 152 | HaikuSeat *seat = HaikuSeat::FromResource(_seat); 153 | seat->GetGlobal()->DoTrack(HaikuSeatGlobal::trackMove); 154 | } 155 | 156 | void HaikuXdgToplevel::HandleResize(struct wl_resource *_seat, uint32_t serial, uint32_t edges) 157 | { 158 | HaikuSeat *seat = HaikuSeat::FromResource(_seat); 159 | seat->GetGlobal()->DoTrack(HaikuSeatGlobal::trackResize, {.resizeEdge = (XdgToplevel::ResizeEdge)edges}); 160 | } 161 | 162 | void HaikuXdgToplevel::HandleSetMaxSize(int32_t width, int32_t height) 163 | { 164 | fSizeLimitsDirty = true; 165 | fMaxWidth = width; 166 | fMaxHeight = height; 167 | } 168 | 169 | void HaikuXdgToplevel::HandleSetMinSize(int32_t width, int32_t height) 170 | { 171 | fSizeLimitsDirty = true; 172 | fMinWidth = width; 173 | fMinHeight = height; 174 | } 175 | 176 | void HaikuXdgToplevel::HandleSetMaximized() 177 | { 178 | } 179 | 180 | void HaikuXdgToplevel::HandleUnsetMaximized() 181 | { 182 | } 183 | 184 | void HaikuXdgToplevel::HandleSetFullscreen(struct wl_resource *output) 185 | { 186 | if (fState.fullscreen) return; 187 | fState.fullscreen = true; 188 | fSizeChanged = true; 189 | fSavedPos = fWindow->Frame(); 190 | BRect screenFrame = BScreen(fWindow).Frame(); 191 | fWindow->MoveTo(screenFrame.LeftTop()); 192 | fWindow->ResizeTo(screenFrame.Width(), screenFrame.Height()); 193 | fWidth = (int32_t)screenFrame.Width() + 1; 194 | fHeight = (int32_t)screenFrame.Height() + 1; 195 | DoSendConfigure(); 196 | XdgSurface()->SendConfigure(XdgSurface()->NextSerial()); 197 | } 198 | 199 | void HaikuXdgToplevel::HandleUnsetFullscreen() 200 | { 201 | if (!fState.fullscreen) return; 202 | fState.fullscreen = false; 203 | fSizeChanged = true; 204 | fWindow->MoveTo(fSavedPos.LeftTop()); 205 | fWindow->ResizeTo(fSavedPos.Width(), fSavedPos.Height()); 206 | fWidth = (int32_t)fSavedPos.Width() + 1; 207 | fHeight = (int32_t)fSavedPos.Height() + 1; 208 | DoSendConfigure(); 209 | XdgSurface()->SendConfigure(XdgSurface()->NextSerial()); 210 | } 211 | 212 | void HaikuXdgToplevel::HandleSetMinimized() 213 | { 214 | } 215 | 216 | 217 | HaikuXdgToplevel *HaikuXdgToplevel::Create(HaikuXdgSurface *xdgSurface, uint32_t id) 218 | { 219 | HaikuXdgToplevel *xdgToplevel = new(std::nothrow) HaikuXdgToplevel(); 220 | if (!xdgToplevel) { 221 | wl_client_post_no_memory(xdgSurface->Client()); 222 | return NULL; 223 | } 224 | if (!xdgToplevel->Init(xdgSurface->Client(), xdgSurface->Version(), id)) { 225 | return NULL; 226 | } 227 | 228 | xdgToplevel->fXdgSurface = xdgSurface; 229 | xdgToplevel->fWindow = new WaylandWindow(xdgToplevel, BRect(), "", B_NO_BORDER_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 0); 230 | xdgSurface->fSurface->AttachWindow(xdgToplevel->fWindow); 231 | 232 | return xdgToplevel; 233 | } 234 | 235 | HaikuXdgToplevel::~HaikuXdgToplevel() 236 | { 237 | fXdgSurface->Surface()->Detach(); 238 | 239 | if (fWindow != NULL) { 240 | fWindow->fToplevel = NULL; 241 | fWindow->PostMessage(B_QUIT_REQUESTED); 242 | //fWindow->Lock(); 243 | //fWindow->Quit(); 244 | fWindow = NULL; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /HaikuXdgToplevel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XdgShell.h" 3 | #include 4 | 5 | 6 | struct HaikuXdgSurface; 7 | class WaylandWindow; 8 | class BWindow; 9 | 10 | class HaikuXdgToplevel: public XdgToplevel { 11 | private: 12 | friend class HaikuSurface; 13 | friend class HaikuXdgSurface; 14 | friend class WaylandWindow; 15 | friend class XdgSurfaceHook; 16 | 17 | HaikuXdgSurface *fXdgSurface{}; 18 | WaylandWindow *fWindow{}; 19 | 20 | bool fSizeLimitsDirty = false; 21 | int32_t fMinWidth = 0, fMinHeight = 0; 22 | int32_t fMaxWidth = 0, fMaxHeight = 0; 23 | int32_t fWidth = 0; 24 | int32_t fHeight = 0; 25 | BRect fSavedPos; 26 | union { 27 | struct { 28 | uint32_t maximized: 1; 29 | uint32_t fullscreen: 1; 30 | uint32_t resizing: 1; 31 | uint32_t activated: 1; 32 | }; 33 | uint32_t val; 34 | } fState {}; 35 | 36 | uint32_t fResizeSerial = 0; 37 | bool fSizeChanged = false; 38 | 39 | public: 40 | virtual ~HaikuXdgToplevel(); 41 | static HaikuXdgToplevel *Create(HaikuXdgSurface *xdg_surface, uint32_t id); 42 | static HaikuXdgToplevel *FromResource(struct wl_resource *resource) {return (HaikuXdgToplevel*)WlResource::FromResource(resource);} 43 | 44 | HaikuXdgSurface *XdgSurface() {return fXdgSurface;} 45 | BWindow *Window() {return (BWindow*)fWindow;} 46 | void MinSize(int32_t &width, int32_t &height) {width = fMinWidth; height = fMinHeight;} 47 | void MaxSize(int32_t &width, int32_t &height) {width = fMaxWidth; height = fMaxHeight;} 48 | void DoSendConfigure(); 49 | 50 | void HandleSetParent(struct wl_resource *parent) override; 51 | void HandleSetTitle(const char *title) override; 52 | void HandleSetAppId(const char *app_id) override; 53 | void HandleShowWindowMenu(struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y) override; 54 | void HandleMove(struct wl_resource *seat, uint32_t serial) override; 55 | void HandleResize(struct wl_resource *seat, uint32_t serial, uint32_t edges) override; 56 | void HandleSetMaxSize(int32_t width, int32_t height) override; 57 | void HandleSetMinSize(int32_t width, int32_t height) override; 58 | void HandleSetMaximized() override; 59 | void HandleUnsetMaximized() override; 60 | void HandleSetFullscreen(struct wl_resource *output) override; 61 | void HandleUnsetFullscreen() override; 62 | void HandleSetMinimized() override; 63 | }; 64 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Source code and other materials are available under following license unless 2 | otherwize is mentioned in individual files. 3 | 4 | 5 | The MIT License 6 | ----------------------------------------------------------- 7 | 8 | Copyright (c) 2022 X512 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /WaylandEnv.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "WaylandServer.h" 4 | #include 5 | #include 6 | 7 | 8 | class WaylandEnv { 9 | private: 10 | BHandler *fHandler; 11 | WaylandEnv **fPointer {}; 12 | sem_t *fWaitSem {}; 13 | 14 | static void Assert(bool cond) {if (!cond) abort();} 15 | 16 | public: 17 | inline WaylandEnv(BHandler *handler, WaylandEnv **pointer = NULL): 18 | fHandler(handler), 19 | fPointer(pointer) 20 | { 21 | if (fPointer != NULL) { 22 | Assert(*fPointer == NULL); 23 | *fPointer = this; 24 | } 25 | 26 | Assert(fHandler->Looper()->CountLocks() == 1); 27 | fHandler->UnlockLooper(); 28 | gServerHandler.LockLooper(); 29 | } 30 | 31 | inline ~WaylandEnv() 32 | { 33 | gServerHandler.UnlockLooper(); 34 | fHandler->LockLooper(); 35 | 36 | if (fPointer != NULL) { 37 | *fPointer = NULL; 38 | 39 | if (fWaitSem != NULL) { 40 | sem_post(fWaitSem); 41 | fWaitSem = NULL; 42 | } 43 | } 44 | } 45 | 46 | static void Wait(WaylandEnv **pointer, BLooper* looper) 47 | { 48 | int32 globalLocked = 0; 49 | while (gServerHandler.Looper()->IsLocked()) { 50 | gServerHandler.UnlockLooper(); 51 | globalLocked++; 52 | } 53 | 54 | int32 localLocked = looper->CountLocks() - 1; 55 | for (int32 i = 0; i < localLocked; i++) { 56 | looper->Unlock(); 57 | } 58 | 59 | while (*pointer != NULL) { 60 | sem_t waitSem; 61 | sem_init(&waitSem, 0, 0); 62 | Assert((*pointer)->fWaitSem == NULL); 63 | (*pointer)->fWaitSem = &waitSem; 64 | 65 | looper->Unlock(); 66 | while (sem_wait(&waitSem) != 0) { 67 | continue; 68 | } 69 | looper->Lock(); 70 | 71 | sem_destroy(&waitSem); 72 | } 73 | 74 | bool wasLooperUnlocked = false; 75 | if (gServerHandler.Looper()->LockWithTimeout(0) == B_OK) { 76 | globalLocked--; 77 | } else { 78 | looper->Unlock(); 79 | localLocked++; 80 | wasLooperUnlocked = true; 81 | } 82 | 83 | while (globalLocked != 0) { 84 | gServerHandler.LockLooper(); 85 | globalLocked--; 86 | } 87 | 88 | while (localLocked != 0) { 89 | looper->Lock(); 90 | localLocked--; 91 | } 92 | 93 | if (wasLooperUnlocked && *pointer != NULL) { 94 | Wait(pointer, looper); 95 | } 96 | } 97 | }; 98 | -------------------------------------------------------------------------------- /WaylandKeycodes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | enum { 5 | KEY_RESERVED = 0, 6 | KEY_ESC = 1, 7 | KEY_1 = 2, 8 | KEY_2 = 3, 9 | KEY_3 = 4, 10 | KEY_4 = 5, 11 | KEY_5 = 6, 12 | KEY_6 = 7, 13 | KEY_7 = 8, 14 | KEY_8 = 9, 15 | KEY_9 = 10, 16 | KEY_0 = 11, 17 | KEY_MINUS = 12, 18 | KEY_EQUAL = 13, 19 | KEY_BACKSPACE = 14, 20 | KEY_TAB = 15, 21 | KEY_Q = 16, 22 | KEY_W = 17, 23 | KEY_E = 18, 24 | KEY_R = 19, 25 | KEY_T = 20, 26 | KEY_Y = 21, 27 | KEY_U = 22, 28 | KEY_I = 23, 29 | KEY_O = 24, 30 | KEY_P = 25, 31 | KEY_LEFTBRACE = 26, 32 | KEY_RIGHTBRACE = 27, 33 | KEY_ENTER = 28, 34 | KEY_LEFTCTRL = 29, 35 | KEY_A = 30, 36 | KEY_S = 31, 37 | KEY_D = 32, 38 | KEY_F = 33, 39 | KEY_G = 34, 40 | KEY_H = 35, 41 | KEY_J = 36, 42 | KEY_K = 37, 43 | KEY_L = 38, 44 | KEY_SEMICOLON = 39, 45 | KEY_APOSTROPHE = 40, 46 | KEY_GRAVE = 41, 47 | KEY_LEFTSHIFT = 42, 48 | KEY_BACKSLASH = 43, 49 | KEY_Z = 44, 50 | KEY_X = 45, 51 | KEY_C = 46, 52 | KEY_V = 47, 53 | KEY_B = 48, 54 | KEY_N = 49, 55 | KEY_M = 50, 56 | KEY_COMMA = 51, 57 | KEY_DOT = 52, 58 | KEY_SLASH = 53, 59 | KEY_RIGHTSHIFT = 54, 60 | KEY_KPASTERISK = 55, 61 | KEY_LEFTALT = 56, 62 | KEY_SPACE = 57, 63 | KEY_CAPSLOCK = 58, 64 | KEY_F1 = 59, 65 | KEY_F2 = 60, 66 | KEY_F3 = 61, 67 | KEY_F4 = 62, 68 | KEY_F5 = 63, 69 | KEY_F6 = 64, 70 | KEY_F7 = 65, 71 | KEY_F8 = 66, 72 | KEY_F9 = 67, 73 | KEY_F10 = 68, 74 | KEY_NUMLOCK = 69, 75 | KEY_SCROLLLOCK = 70, 76 | KEY_KP7 = 71, 77 | KEY_KP8 = 72, 78 | KEY_KP9 = 73, 79 | KEY_KPMINUS = 74, 80 | KEY_KP4 = 75, 81 | KEY_KP5 = 76, 82 | KEY_KP6 = 77, 83 | KEY_KPPLUS = 78, 84 | KEY_KP1 = 79, 85 | KEY_KP2 = 80, 86 | KEY_KP3 = 81, 87 | KEY_KP0 = 82, 88 | KEY_KPDOT = 83, 89 | KEY_ZENKAKUHANKAKU = 85, 90 | KEY_102ND = 86, 91 | KEY_F11 = 87, 92 | KEY_F12 = 88, 93 | KEY_RO = 89, 94 | KEY_KATAKANA = 90, 95 | KEY_HIRAGANA = 91, 96 | KEY_HENKAN = 92, 97 | KEY_KATAKANAHIRAGANA = 93, 98 | KEY_MUHENKAN = 94, 99 | KEY_KPJPCOMMA = 95, 100 | KEY_KPENTER = 96, 101 | KEY_RIGHTCTRL = 97, 102 | KEY_KPSLASH = 98, 103 | KEY_SYSRQ = 99, 104 | KEY_RIGHTALT = 100, 105 | KEY_LINEFEED = 101, 106 | KEY_HOME = 102, 107 | KEY_UP = 103, 108 | KEY_PAGEUP = 104, 109 | KEY_LEFT = 105, 110 | KEY_RIGHT = 106, 111 | KEY_END = 107, 112 | KEY_DOWN = 108, 113 | KEY_PAGEDOWN = 109, 114 | KEY_INSERT = 110, 115 | KEY_DELETE = 111, 116 | KEY_MACRO = 112, 117 | KEY_MUTE = 113, 118 | KEY_VOLUMEDOWN = 114, 119 | KEY_VOLUMEUP = 115, 120 | KEY_POWER = 116, 121 | KEY_KPEQUAL = 117, 122 | KEY_KPPLUSMINUS = 118, 123 | KEY_PAUSE = 119, 124 | KEY_SCALE = 120, 125 | KEY_KPCOMMA = 121, 126 | KEY_HANGEUL = 122, 127 | KEY_HANGUEL = KEY_HANGEUL, 128 | KEY_HANJA = 123, 129 | KEY_YEN = 124, 130 | KEY_LEFTMETA = 125, 131 | KEY_RIGHTMETA = 126, 132 | KEY_COMPOSE = 127, 133 | }; 134 | 135 | enum { 136 | BTN_LEFT = 0x110, 137 | BTN_RIGHT = 0x111, 138 | BTN_MIDDLE = 0x112, 139 | BTN_SIDE = 0x113, 140 | BTN_EXTRA = 0x114, 141 | BTN_FORWARD = 0x115, 142 | BTN_BACK = 0x116, 143 | BTN_TASK = 0x117, 144 | }; 145 | -------------------------------------------------------------------------------- /WaylandServer.cpp: -------------------------------------------------------------------------------- 1 | #include "WaylandServer.h" 2 | #include "Wayland.h" 3 | #include "HaikuShm.h" 4 | #include "HaikuCompositor.h" 5 | #include "HaikuSubcompositor.h" 6 | #include "HaikuXdgShell.h" 7 | #include "HaikuXdgSurface.h" 8 | #include "HaikuXdgToplevel.h" 9 | #include "HaikuOutput.h" 10 | #include "HaikuDataDeviceManager.h" 11 | #include "HaikuSeat.h" 12 | #include "HaikuTextInput.h" 13 | #include "HaikuServerDecoration.h" 14 | #include "WaylandEnv.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include "AppKitPtrs.h" 25 | 26 | 27 | static void Assert(bool cond) {if (!cond) abort();} 28 | 29 | extern "C" void 30 | wl_client_dispatch(struct wl_client *client, struct wl_closure *closure); 31 | 32 | typedef int (*client_enqueue_proc)(void *client_display, struct wl_closure *closure); 33 | 34 | 35 | static struct wl_display *sDisplay; 36 | 37 | ServerHandler gServerHandler; 38 | BMessenger gServerMessenger; 39 | 40 | ServerHandler::ServerHandler(): BHandler("server") 41 | {} 42 | 43 | void ServerHandler::MessageReceived(BMessage *msg) 44 | { 45 | switch (msg->what) { 46 | case closureSendMsg: { 47 | struct wl_client *client; 48 | msg->FindPointer("client", (void**)&client); 49 | struct wl_closure *closure; 50 | msg->FindPointer("closure", (void**)&closure); 51 | wl_client_dispatch(client, closure); 52 | return; 53 | } 54 | default: 55 | break; 56 | } 57 | BHandler::MessageReceived(msg); 58 | } 59 | 60 | 61 | class Application: public BApplication { 62 | private: 63 | // TODO: support multiple clients 64 | struct wl_client *fClient{}; 65 | 66 | public: 67 | Application(); 68 | virtual ~Application() = default; 69 | 70 | void AddClient(struct wl_client *client); 71 | 72 | thread_id Run() override; 73 | void Quit() override; 74 | void MessageReceived(BMessage *msg) override; 75 | }; 76 | 77 | Application::Application(): BApplication("application/x-vnd.Wayland-App") 78 | { 79 | } 80 | 81 | void Application::AddClient(struct wl_client *client) 82 | { 83 | fClient = client; 84 | } 85 | 86 | thread_id Application::Run() 87 | { 88 | return BLooper::Run(); 89 | } 90 | 91 | void Application::Quit() 92 | { 93 | BApplication::Quit(); 94 | exit(0); 95 | } 96 | 97 | void Application::MessageReceived(BMessage *msg) 98 | { 99 | switch (msg->what) { 100 | case B_KEY_MAP_LOADED: 101 | if (fClient == NULL) return; 102 | WaylandEnv env(this); 103 | HaikuSeatGlobal *seat = HaikuGetSeat(fClient); 104 | if (seat == NULL) return; 105 | seat->UpdateKeymap(); 106 | return; 107 | } 108 | return BApplication::MessageReceived(msg); 109 | } 110 | 111 | 112 | //#pragma mark - entry points 113 | 114 | extern "C" _EXPORT int wl_ips_client_connected(void **clientOut, void *clientDisplay, client_enqueue_proc display_enqueue) 115 | { 116 | if (be_app == NULL) { 117 | new Application(); 118 | be_app->Run(); 119 | } 120 | if (gServerHandler.Looper() == NULL) { 121 | AppKitPtrs::LockedPtr(be_app)->AddHandler(&gServerHandler); 122 | gServerMessenger.SetTo(&gServerHandler); 123 | } 124 | 125 | fprintf(stderr, "wl_ips_client_connected\n"); 126 | if (sDisplay == NULL) { 127 | sDisplay = wl_display_create(); 128 | 129 | HaikuSeatGlobal *seat {}; 130 | 131 | Assert(HaikuShmGlobal::Create(sDisplay) != NULL); 132 | Assert(HaikuCompositorGlobal::Create(sDisplay) != NULL); 133 | Assert(HaikuSubcompositorGlobal::Create(sDisplay) != NULL); 134 | Assert(HaikuOutputGlobal::Create(sDisplay) != NULL); 135 | Assert(HaikuDataDeviceManagerGlobal::Create(sDisplay) != NULL); 136 | Assert((seat = HaikuSeatGlobal::Create(sDisplay)) != NULL); 137 | Assert(HaikuTextInputGlobal::Create(sDisplay, seat) != NULL); 138 | Assert(HaikuXdgShell::Create(sDisplay) != NULL); 139 | Assert(HaikuServerDecorationManagerGlobal::Create(sDisplay) != NULL); 140 | } 141 | fprintf(stderr, "display: %p\n", sDisplay); 142 | struct wl_client *client = wl_client_create_ips(sDisplay, clientDisplay, display_enqueue); 143 | fprintf(stderr, "client: %p\n", client); 144 | static_cast(be_app)->AddClient(client); 145 | 146 | *clientOut = client; 147 | 148 | return 0; 149 | /* 150 | wl_client_destroy(client); 151 | wl_display_destroy(display); 152 | */ 153 | } 154 | 155 | extern "C" _EXPORT int wl_ips_closure_send(void *clientIn, struct wl_closure *closure) 156 | { 157 | struct wl_client *client = (struct wl_client*)clientIn; 158 | 159 | if (true) { 160 | BMessage msg(ServerHandler::closureSendMsg); 161 | msg.AddPointer("client", client); 162 | msg.AddPointer("closure", closure); 163 | gServerMessenger.SendMessage(&msg); 164 | } else { 165 | wl_client_dispatch(client, closure); 166 | } 167 | 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /WaylandServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | class ServerHandler: public BHandler { 8 | public: 9 | enum { 10 | closureSendMsg = 1, 11 | }; 12 | 13 | ServerHandler(); 14 | virtual ~ServerHandler() = default; 15 | 16 | void MessageReceived(BMessage *msg) final; 17 | }; 18 | 19 | extern ServerHandler gServerHandler; 20 | extern BMessenger gServerMessenger; 21 | -------------------------------------------------------------------------------- /WlGlobal.cpp: -------------------------------------------------------------------------------- 1 | #include "WlGlobal.h" 2 | 3 | 4 | void WlGlocal::Binder(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id) 5 | { 6 | static_cast(data)->Bind(wl_client, version, id); 7 | } 8 | 9 | WlGlocal::~WlGlocal() 10 | { 11 | if (fGlobal != NULL) { 12 | wl_global_destroy(fGlobal); 13 | } 14 | } 15 | 16 | bool WlGlocal::Init(struct wl_display *display, const struct wl_interface *interface, uint32_t version) 17 | { 18 | wl_global *global = wl_global_create(display, interface, version, this, WlGlocal::Binder); 19 | if (global == NULL) return false; 20 | fGlobal = global; 21 | return true; 22 | } 23 | -------------------------------------------------------------------------------- /WlGlobal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | class WlGlocal { 6 | private: 7 | struct wl_global *fGlobal = NULL; 8 | 9 | static void Binder(struct wl_client *wl_client, void *data, uint32_t version, uint32_t id); 10 | 11 | public: 12 | virtual ~WlGlocal(); 13 | bool Init(struct wl_display *display, const struct wl_interface *interface, uint32_t version); 14 | 15 | virtual void Bind(struct wl_client *wl_client, uint32_t version, uint32_t id) = 0; 16 | 17 | static WlGlocal *FromGlocal(struct wl_global *global) {return static_cast(wl_global_get_user_data(global));} 18 | struct wl_global *ToGlocal() const {return fGlobal;} 19 | }; 20 | -------------------------------------------------------------------------------- /WlResource.cpp: -------------------------------------------------------------------------------- 1 | #include "WlResource.h" 2 | #include 3 | #include 4 | 5 | 6 | void WlResource::Destructor(struct wl_resource *resource) 7 | { 8 | delete WlResource::FromResource(resource); 9 | } 10 | 11 | int WlResource::Dispatcher(const void *impl, void *resource, uint32_t opcode, const struct wl_message *message, union wl_argument *args) 12 | { 13 | return WlResource::FromResource((struct wl_resource*)resource)->Dispatch(opcode, message, args); 14 | } 15 | 16 | bool WlResource::Init(struct wl_client *wl_client, uint32_t version, uint32_t id) 17 | { 18 | fResource = wl_resource_create(wl_client, Interface(), version, id); 19 | if (fResource == NULL) { 20 | wl_client_post_no_memory(wl_client); 21 | return false; 22 | } 23 | wl_resource_set_dispatcher(fResource, Dispatcher, NULL, this, Destructor); 24 | return true; 25 | } 26 | 27 | void WlResource::Destroy() 28 | { 29 | wl_resource_destroy(ToResource()); 30 | } 31 | 32 | WlResource *WlResource::FromResource(struct wl_resource *resource) 33 | { 34 | if (resource == NULL) 35 | return NULL; 36 | WlResource *resourceOut = (WlResource*)wl_resource_get_user_data(resource); 37 | if (resourceOut == NULL || !wl_resource_instance_of(resource, resourceOut->Interface(), NULL)) { 38 | return NULL; 39 | } 40 | return resourceOut; 41 | } 42 | 43 | int WlResource::Dispatch(uint32_t opcode, const struct wl_message *message, union wl_argument *args) 44 | { 45 | return -1; 46 | } 47 | -------------------------------------------------------------------------------- /WlResource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class WlResource { 5 | private: 6 | struct wl_resource *fResource = NULL; 7 | 8 | static void Destructor(struct wl_resource *resource); 9 | static int Dispatcher(const void *impl, void *resource, uint32_t opcode, const struct wl_message *message, union wl_argument *args); 10 | 11 | public: 12 | virtual ~WlResource() = default; 13 | bool Init(struct wl_client *wl_client, uint32_t version, uint32_t id); 14 | void Destroy(); 15 | virtual const struct wl_interface *Interface() const = 0; 16 | virtual int Dispatch(uint32_t opcode, const struct wl_message *message, union wl_argument *args); 17 | static WlResource *FromResource(struct wl_resource *resource); 18 | struct wl_resource *ToResource() const {return fResource;} 19 | struct wl_client *Client() const {return wl_resource_get_client(fResource);} 20 | uint32_t Id() const {return wl_resource_get_id(fResource);} 21 | uint32_t Version() const {return wl_resource_get_version(fResource);} 22 | }; 23 | -------------------------------------------------------------------------------- /XkbKeymap.cpp: -------------------------------------------------------------------------------- 1 | #include "XkbKeymap.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "WaylandKeycodes.h" 15 | 16 | 17 | static void RandName(char *buf) 18 | { 19 | struct timespec ts; 20 | clock_gettime(CLOCK_REALTIME, &ts); 21 | long r = ts.tv_nsec; 22 | for (int i = 0; i < 6; ++i) { 23 | buf[i] = 'A' + (r&15) + (r&16)*2; 24 | r >>= 5; 25 | } 26 | } 27 | 28 | static int CreateMemoryFile() 29 | { 30 | char name[] = "/wayland-XXXXXX"; 31 | int retries = 100; 32 | 33 | do { 34 | RandName(name + strlen(name) - 6); 35 | --retries; 36 | int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); 37 | if (fd >= 0) { 38 | shm_unlink(name); 39 | return fd; 40 | } 41 | } while (retries > 0 && errno == EEXIST); 42 | 43 | return -1; 44 | } 45 | 46 | 47 | static void WriteSymbol(FILE *file, uint32 haikuKey, char *keyBuffer, uint32 offset) 48 | { 49 | switch (haikuKey) { 50 | case 0x02: fprintf(file, "F1"); return; 51 | case 0x03: fprintf(file, "F2"); return; 52 | case 0x04: fprintf(file, "F3"); return; 53 | case 0x05: fprintf(file, "F4"); return; 54 | case 0x06: fprintf(file, "F5"); return; 55 | case 0x07: fprintf(file, "F6"); return; 56 | case 0x08: fprintf(file, "F7"); return; 57 | case 0x09: fprintf(file, "F8"); return; 58 | case 0x0a: fprintf(file, "F9"); return; 59 | case 0x0b: fprintf(file, "F10"); return; 60 | case 0x0c: fprintf(file, "F11"); return; 61 | case 0x0d: fprintf(file, "F12"); return; 62 | default: break; 63 | } 64 | uint32 codepoint = 0; 65 | uint32 len = (uint8)keyBuffer[offset]; 66 | if (len > 0) { 67 | const char *bytes = &keyBuffer[offset + 1]; 68 | switch (bytes[0]) { 69 | case B_BACKSPACE: fprintf(file, "BackSpace"); return; 70 | case B_RETURN: fprintf(file, "Return"); return; 71 | case B_TAB: fprintf(file, "Tab"); return; 72 | case B_ESCAPE: fprintf(file, "Escape"); return; 73 | case B_LEFT_ARROW: fprintf(file, "Left"); return; 74 | case B_RIGHT_ARROW: fprintf(file, "Right"); return; 75 | case B_UP_ARROW: fprintf(file, "Up"); return; 76 | case B_DOWN_ARROW: fprintf(file, "Down"); return; 77 | case B_INSERT: fprintf(file, "Insert"); return; 78 | case B_DELETE: fprintf(file, "Delete"); return; 79 | case B_HOME: fprintf(file, "Home"); return; 80 | case B_END: fprintf(file, "End"); return; 81 | case B_PAGE_UP: fprintf(file, "Prior"); return; 82 | case B_PAGE_DOWN: fprintf(file, "Next"); return; 83 | default: break; 84 | } 85 | codepoint = UTF8ToCharCode(&bytes); 86 | } 87 | fprintf(file, "U%04" B_PRIx32, codepoint); 88 | } 89 | 90 | static void GenerateSymbols(FILE *file, key_map *map, char *keyBuffer) 91 | { 92 | for (uint32 haikuKey = 0x01; haikuKey <= 0x6b; haikuKey++) { 93 | uint32 wlKey = FromHaikuKeyCode(haikuKey); 94 | if (wlKey == 0) continue; 95 | fprintf(file, "\t\tkey {type = \"Haiku\", symbols[Group1] = [", wlKey + 8); 96 | WriteSymbol(file, haikuKey, keyBuffer, map->normal_map[haikuKey]); fprintf(file, ", "); 97 | WriteSymbol(file, haikuKey, keyBuffer, map->shift_map[haikuKey]); fprintf(file, ", "); 98 | WriteSymbol(file, haikuKey, keyBuffer, map->caps_map[haikuKey]); fprintf(file, ", "); 99 | WriteSymbol(file, haikuKey, keyBuffer, map->caps_shift_map[haikuKey]); fprintf(file, ", "); 100 | WriteSymbol(file, haikuKey, keyBuffer, map->option_map[haikuKey]); fprintf(file, ", "); 101 | WriteSymbol(file, haikuKey, keyBuffer, map->option_shift_map[haikuKey]); fprintf(file, ", "); 102 | WriteSymbol(file, haikuKey, keyBuffer, map->option_caps_map[haikuKey]); fprintf(file, ", "); 103 | WriteSymbol(file, haikuKey, keyBuffer, map->option_caps_shift_map[haikuKey]); //fprintf(file, ", "); 104 | //WriteSymbol(file, haikuKey, keyBuffer, map->control_map[haikuKey]); 105 | fprintf(file, "]};\n"); 106 | } 107 | } 108 | 109 | status_t ProduceXkbKeymap(int &fd) 110 | { 111 | key_map *map; 112 | char *keyBuffer; 113 | get_key_map(&map, &keyBuffer); 114 | MemoryDeleter mapDeleter(map); 115 | MemoryDeleter keyBufferDeleter(keyBuffer); 116 | if (!mapDeleter.IsSet() || !keyBufferDeleter.IsSet()) 117 | return B_NO_MEMORY; 118 | 119 | fd = CreateMemoryFile(); 120 | FileDescriptorCloser fdCloser(fd); 121 | if (!fdCloser.IsSet()) 122 | return B_ERROR; // Use `errno`? 123 | 124 | FILE *file = fdopen(dup(fd), "w"); 125 | FileCloser fileCloser(file); 126 | if (!fileCloser.IsSet()) 127 | return B_ERROR; // Use `errno`? 128 | 129 | fprintf(file, "xkb_keymap {\n"); 130 | 131 | fprintf(file, "\txkb_keycodes \"(unnamed)\" {\n"); 132 | int minimum = 8; 133 | int maximum = 708; 134 | fprintf(file, "\t\tminimum = %d;\n", minimum); 135 | fprintf(file, "\t\tmaximum = %d;\n", maximum); 136 | for (int i = minimum + 1; i <= maximum; i++) { 137 | fprintf(file, "\t\t = %d;\n", i, i); 138 | } 139 | fprintf(file, "\t};\n"); 140 | 141 | fprintf(file, "\txkb_types \"(unnamed)\" {\n"); 142 | fprintf(file, "\t\tvirtual_modifiers NumLock,Alt,LevelThree,LevelFive,Meta,Super,Hyper,ScrollLock;\n"); 143 | fprintf(file, "\t\ttype \"Haiku\" {\n"); 144 | fprintf(file, "\t\t\tmodifiers = Shift+Lock+Mod4;\n"); 145 | fprintf(file, "\t\t\tmap[Shift] = 2;\n"); 146 | fprintf(file, "\t\t\tmap[Lock] = 3;\n"); 147 | fprintf(file, "\t\t\tmap[Shift+Lock] = 4;\n"); 148 | fprintf(file, "\t\t\tmap[Mod4] = 5;\n"); 149 | fprintf(file, "\t\t\tmap[Mod4+Shift] = 6;\n"); 150 | fprintf(file, "\t\t\tmap[Mod4+Lock] = 7;\n"); 151 | fprintf(file, "\t\t\tmap[Mod4+Lock+Shift] = 8;\n"); 152 | //fprintf(file, "\t\t\tmap[Control] = 9;\n"); 153 | fprintf(file, "\t\t\tlevel_name[1] = \"Base\";\n"); 154 | fprintf(file, "\t\t\tlevel_name[2] = \"Shift\";\n"); 155 | fprintf(file, "\t\t\tlevel_name[3] = \"Caps\";\n"); 156 | fprintf(file, "\t\t\tlevel_name[4] = \"Caps+Shift\";\n"); 157 | fprintf(file, "\t\t\tlevel_name[5] = \"Option\";\n"); 158 | fprintf(file, "\t\t\tlevel_name[6] = \"Option+Shift\";\n"); 159 | fprintf(file, "\t\t\tlevel_name[7] = \"Option+Caps\";\n"); 160 | fprintf(file, "\t\t\tlevel_name[8] = \"Option+Caps+Shift\";\n"); 161 | //fprintf(file, "\t\t\tlevel_name[9] = \"Control\";\n"); 162 | fprintf(file, "\t\t};\n"); 163 | fprintf(file, "\t};\n"); 164 | 165 | fprintf(file, "\txkb_compatibility \"(unnamed)\" {\n"); 166 | fprintf(file, "\t};\n"); 167 | 168 | fprintf(file, "\txkb_symbols \"(unnamed)\" {\n"); 169 | fprintf(file, "\t\tname[Group1]=\"Unnamed\";\n"); 170 | GenerateSymbols(file, map, keyBuffer); 171 | fprintf(file, "\t\tmodifier_map Shift {, };\n"); 172 | fprintf(file, "\t\tmodifier_map Lock {};\n"); 173 | fprintf(file, "\t\tmodifier_map Control {, };\n"); 174 | fprintf(file, "\t\tmodifier_map Mod1 {, , , };\n"); // Alt 175 | fprintf(file, "\t\tmodifier_map Mod2 {};\n"); 176 | fprintf(file, "\t\tmodifier_map Mod3 {};\n"); 177 | fprintf(file, "\t\tmodifier_map Mod4 {, , , };\n"); // Option 178 | fprintf(file, "\t\tmodifier_map Mod5 {};\n"); 179 | fprintf(file, "\t};\n"); 180 | 181 | fprintf(file, "};\n"); 182 | 183 | fputc(0, file); 184 | 185 | fdCloser.Detach(); 186 | return B_OK; 187 | } 188 | -------------------------------------------------------------------------------- /XkbKeymap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | uint32_t FromHaikuKeyCode(uint32 haikuKey); 6 | 7 | status_t ProduceXkbKeymap(int &fd); 8 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('WaylandServer', 'c', 'cpp', 2 | version : '0.1', 3 | default_options : ['warning_level=3', 'cpp_std=c++2a'] 4 | ) 5 | 6 | add_project_arguments('-Wno-unused-parameter', language: 'cpp') 7 | add_project_arguments('-Wno-unused-variable', language: 'cpp') 8 | 9 | cpp = meson.get_compiler('cpp') 10 | 11 | arch = build_machine.cpu_family() 12 | if arch == 'aarch64' 13 | arch = 'arm64' 14 | endif 15 | 16 | wlserverdep = dependency('wayland-server') 17 | wlprotocolsdep = dependency('wayland-protocols') 18 | 19 | wl_dir = wlserverdep.get_variable('pkgdatadir') 20 | wl_protocol_dir = wlprotocolsdep.get_variable('pkgdatadir') 21 | 22 | wayland_scanner_dep = dependency('wayland-scanner', native: true) 23 | wayland_scanner = find_program(wayland_scanner_dep.get_variable('wayland_scanner'), native: true) 24 | 25 | protocols = { 26 | # Stable upstream protocols 27 | 'xdg-shell': wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', 28 | 'presentation-time': wl_protocol_dir / 'stable/presentation-time/presentation-time.xml', 29 | 'viewporter': wl_protocol_dir / 'stable/viewporter/viewporter.xml', 30 | 'activation-v1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', 31 | 'text-input-unstable-v3': wl_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml', 32 | 'server-decoration': 'protocols/server-decoration.xml', 33 | } 34 | 35 | wl_files = [] 36 | protocols_code = {} 37 | protocols_server_header = {} 38 | protocols_client_header = {} 39 | foreach name, path : protocols 40 | code = custom_target( 41 | name.underscorify() + '_c', 42 | input: path, 43 | output: '@BASENAME@-protocol.c', 44 | command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], 45 | ) 46 | wl_files += code 47 | 48 | server_header = custom_target( 49 | name.underscorify() + '_server_h', 50 | input: path, 51 | output: '@BASENAME@-protocol.h', 52 | command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], 53 | ) 54 | wl_files += server_header 55 | 56 | client_header = custom_target( 57 | name.underscorify() + '_client_h', 58 | input: path, 59 | output: '@BASENAME@-client-protocol.h', 60 | command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], 61 | build_by_default: false, 62 | ) 63 | 64 | protocols_code += { name: code } 65 | protocols_server_header += { name: server_header } 66 | protocols_client_header += { name: client_header } 67 | endforeach 68 | 69 | protocols_cpp = { 70 | 'Wayland': wl_dir / 'wayland.xml', 71 | 'XdgShell': wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', 72 | 'PresentationTime': wl_protocol_dir / 'stable/presentation-time/presentation-time.xml', 73 | 'Viewporter': wl_protocol_dir / 'stable/viewporter/viewporter.xml', 74 | 'XdgActivationV1': wl_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', 75 | 'TextInputUnstableV3': wl_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml', 76 | 'ServerDecoration': 'protocols/server-decoration.xml', 77 | } 78 | 79 | foreach name, path : protocols_cpp 80 | code = custom_target( 81 | name + '_cpp', 82 | input: path, 83 | output: name + '.cpp', 84 | command: [wayland_scanner, 'private-code-cpp', '@INPUT@', '@OUTPUT@'], 85 | ) 86 | wl_files += code 87 | 88 | server_header = custom_target( 89 | name + '_h', 90 | input: path, 91 | output: name + '.h', 92 | command: [wayland_scanner, 'server-header-cpp', '@INPUT@', '@OUTPUT@'], 93 | ) 94 | wl_files += server_header 95 | endforeach 96 | 97 | 98 | shared_library('wayland-server-inproc', 99 | [ 100 | 'WaylandServer.cpp', 101 | 'WlResource.cpp', 102 | 'WlGlobal.cpp', 103 | 'HaikuShm.cpp', 104 | 'HaikuCompositor.cpp', 105 | 'HaikuSubcompositor.cpp', 106 | 'HaikuXdgShell.cpp', 107 | 'HaikuXdgPositioner.cpp', 108 | 'HaikuXdgSurface.cpp', 109 | 'HaikuXdgToplevel.cpp', 110 | 'HaikuXdgPopup.cpp', 111 | 'HaikuServerDecoration.cpp', 112 | 'HaikuOutput.cpp', 113 | 'HaikuSeat.cpp', 114 | 'HaikuTextInput.cpp', 115 | 'XkbKeymap.cpp', 116 | 'HaikuDataDeviceManager.cpp', 117 | wl_files 118 | ], 119 | name_prefix: '', 120 | include_directories: [ 121 | '/boot/system/develop/headers/private/shared', 122 | '/boot/system/develop/headers/private/interface', 123 | '/boot/system/develop/headers/private/system', 124 | '/boot/system/develop/headers/private/system/arch/' + arch, 125 | ], 126 | dependencies: [ 127 | cpp.find_library('be'), 128 | wlserverdep, 129 | ], 130 | gnu_symbol_visibility: 'hidden', 131 | install : true 132 | ) 133 | -------------------------------------------------------------------------------- /protocols/server-decoration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | . 18 | ]]> 19 | 20 | 21 | This interface allows to coordinate whether the server should create 22 | a server-side window decoration around a wl_surface representing a 23 | shell surface (wl_shell_surface or similar). By announcing support 24 | for this interface the server indicates that it supports server 25 | side decorations. 26 | 27 | 28 | 29 | When a client creates a server-side decoration object it indicates 30 | that it supports the protocol. The client is supposed to tell the 31 | server whether it wants server-side decorations or will provide 32 | client-side decorations. 33 | 34 | If the client does not create a server-side decoration object for 35 | a surface the server interprets this as lack of support for this 36 | protocol and considers it as client-side decorated. Nevertheless a 37 | client-side decorated surface should use this protocol to indicate 38 | to the server that it does not want a server-side deco. 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | This event is emitted directly after binding the interface. It contains 52 | the default mode for the decoration. When a new server decoration object 53 | is created this new object will be in the default mode until the first 54 | request_mode is requested. 55 | 56 | The server may change the default mode at any time. 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | This event is emitted directly after the decoration is created and 78 | represents the base decoration policy by the server. E.g. a server 79 | which wants all surfaces to be client-side decorated will send Client, 80 | a server which wants server-side decoration will send Server. 81 | 82 | The client can request a different mode through the decoration request. 83 | The server will acknowledge this by another event with the same mode. So 84 | even if a server prefers server-side decoration it's possible to force a 85 | client-side decoration. 86 | 87 | The server may emit this event at any time. In this case the client can 88 | again request a different mode. It's the responsibility of the server to 89 | prevent a feedback loop. 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /util/DoublyLinkedList.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2005-2009, Ingo Weinhold, bonefish@users.sf.net. 3 | * Copyright 2006-2009, Axel Dörfler, axeld@pinc-software.de. 4 | * 5 | * Distributed under the terms of the MIT License. 6 | */ 7 | #ifndef KERNEL_UTIL_DOUBLY_LINKED_LIST_H 8 | #define KERNEL_UTIL_DOUBLY_LINKED_LIST_H 9 | 10 | 11 | #include 12 | 13 | #ifdef _KERNEL_MODE 14 | # include 15 | # include 16 | 17 | # if !defined(_BOOT_MODE) && KDEBUG 18 | # define DEBUG_DOUBLY_LINKED_LIST KDEBUG 19 | # endif 20 | #endif 21 | 22 | 23 | #ifdef __cplusplus 24 | 25 | // DoublyLinkedListLink 26 | template 27 | class DoublyLinkedListLink { 28 | public: 29 | Element* next; 30 | Element* previous; 31 | }; 32 | 33 | // DoublyLinkedListLinkImpl 34 | template 35 | class DoublyLinkedListLinkImpl { 36 | private: 37 | typedef DoublyLinkedListLink DLL_Link; 38 | 39 | public: 40 | DLL_Link* GetDoublyLinkedListLink() 41 | { return &fDoublyLinkedListLink; } 42 | const DLL_Link* GetDoublyLinkedListLink() const 43 | { return &fDoublyLinkedListLink; } 44 | 45 | private: 46 | DLL_Link fDoublyLinkedListLink; 47 | }; 48 | 49 | // DoublyLinkedListStandardGetLink 50 | template 51 | class DoublyLinkedListStandardGetLink { 52 | private: 53 | typedef DoublyLinkedListLink Link; 54 | 55 | public: 56 | inline Link* operator()(Element* element) const 57 | { 58 | return element->GetDoublyLinkedListLink(); 59 | } 60 | 61 | inline const Link* operator()(const Element* element) const 62 | { 63 | return element->GetDoublyLinkedListLink(); 64 | } 65 | }; 66 | 67 | // DoublyLinkedListMemberGetLink 68 | template Element::* LinkMember = &Element::fLink> 70 | class DoublyLinkedListMemberGetLink { 71 | private: 72 | typedef DoublyLinkedListLink Link; 73 | 74 | public: 75 | inline Link* operator()(Element* element) const 76 | { 77 | return &(element->*LinkMember); 78 | } 79 | 80 | inline const Link* operator()(const Element* element) const 81 | { 82 | return &(element->*LinkMember); 83 | } 84 | }; 85 | 86 | // DoublyLinkedListCLink - interface to struct list 87 | template 88 | class DoublyLinkedListCLink { 89 | private: 90 | typedef DoublyLinkedListLink Link; 91 | 92 | public: 93 | inline Link* operator()(Element* element) const 94 | { 95 | return (Link*)&element->link; 96 | } 97 | 98 | inline const Link* operator()(const Element* element) const 99 | { 100 | return (const Link*)&element->link; 101 | } 102 | }; 103 | 104 | // for convenience 105 | #define DOUBLY_LINKED_LIST_TEMPLATE_LIST \ 106 | template 107 | #define DOUBLY_LINKED_LIST_CLASS_NAME DoublyLinkedList 108 | 109 | // DoublyLinkedList 110 | template > 112 | class DoublyLinkedList { 113 | private: 114 | typedef DoublyLinkedList List; 115 | typedef DoublyLinkedListLink Link; 116 | 117 | public: 118 | class Iterator { 119 | public: 120 | Iterator(List* list) 121 | : 122 | fList(list) 123 | { 124 | Rewind(); 125 | } 126 | 127 | Iterator() 128 | { 129 | } 130 | 131 | Iterator(const Iterator &other) 132 | { 133 | *this = other; 134 | } 135 | 136 | bool HasNext() const 137 | { 138 | return fNext; 139 | } 140 | 141 | Element* Next() 142 | { 143 | fCurrent = fNext; 144 | if (fNext) 145 | fNext = fList->GetNext(fNext); 146 | return fCurrent; 147 | } 148 | 149 | Element* Current() 150 | { 151 | return fCurrent; 152 | } 153 | 154 | Element* Remove() 155 | { 156 | Element* element = fCurrent; 157 | if (fCurrent) { 158 | fList->Remove(fCurrent); 159 | fCurrent = NULL; 160 | } 161 | return element; 162 | } 163 | 164 | Iterator &operator=(const Iterator& other) 165 | { 166 | fList = other.fList; 167 | fCurrent = other.fCurrent; 168 | fNext = other.fNext; 169 | return *this; 170 | } 171 | 172 | void Rewind() 173 | { 174 | fCurrent = NULL; 175 | fNext = fList->First(); 176 | } 177 | 178 | private: 179 | List* fList; 180 | Element* fCurrent; 181 | Element* fNext; 182 | }; 183 | 184 | class ConstIterator { 185 | public: 186 | ConstIterator(const List* list) 187 | : 188 | fList(list) 189 | { 190 | Rewind(); 191 | } 192 | 193 | ConstIterator(const ConstIterator& other) 194 | { 195 | *this = other; 196 | } 197 | 198 | bool HasNext() const 199 | { 200 | return fNext; 201 | } 202 | 203 | Element* Next() 204 | { 205 | Element* element = fNext; 206 | if (fNext) 207 | fNext = fList->GetNext(fNext); 208 | return element; 209 | } 210 | 211 | ConstIterator& operator=(const ConstIterator& other) 212 | { 213 | fList = other.fList; 214 | fNext = other.fNext; 215 | return *this; 216 | } 217 | 218 | void Rewind() 219 | { 220 | fNext = fList->First(); 221 | } 222 | 223 | private: 224 | const List* fList; 225 | Element* fNext; 226 | }; 227 | 228 | class ReverseIterator { 229 | public: 230 | ReverseIterator(List* list) 231 | : 232 | fList(list) 233 | { 234 | Rewind(); 235 | } 236 | 237 | ReverseIterator(const ReverseIterator& other) 238 | { 239 | *this = other; 240 | } 241 | 242 | bool HasNext() const 243 | { 244 | return fNext; 245 | } 246 | 247 | Element* Next() 248 | { 249 | fCurrent = fNext; 250 | if (fNext) 251 | fNext = fList->GetPrevious(fNext); 252 | return fCurrent; 253 | } 254 | 255 | Element* Remove() 256 | { 257 | Element* element = fCurrent; 258 | if (fCurrent) { 259 | fList->Remove(fCurrent); 260 | fCurrent = NULL; 261 | } 262 | return element; 263 | } 264 | 265 | ReverseIterator &operator=(const ReverseIterator& other) 266 | { 267 | fList = other.fList; 268 | fCurrent = other.fCurrent; 269 | fNext = other.fNext; 270 | return *this; 271 | } 272 | 273 | void Rewind() 274 | { 275 | fCurrent = NULL; 276 | fNext = fList->Last(); 277 | } 278 | 279 | private: 280 | List* fList; 281 | Element* fCurrent; 282 | Element* fNext; 283 | }; 284 | 285 | class ConstReverseIterator { 286 | public: 287 | ConstReverseIterator(const List* list) 288 | : 289 | fList(list) 290 | { 291 | Rewind(); 292 | } 293 | 294 | ConstReverseIterator(const ConstReverseIterator& other) 295 | { 296 | *this = other; 297 | } 298 | 299 | bool HasNext() const 300 | { 301 | return fNext; 302 | } 303 | 304 | Element* Next() 305 | { 306 | Element* element = fNext; 307 | if (fNext) 308 | fNext = fList->GetPrevious(fNext); 309 | return element; 310 | } 311 | 312 | ConstReverseIterator& operator=(const ConstReverseIterator& other) 313 | { 314 | fList = other.fList; 315 | fNext = other.fNext; 316 | return *this; 317 | } 318 | 319 | void Rewind() 320 | { 321 | fNext = fList->Last(); 322 | } 323 | 324 | private: 325 | const List* fList; 326 | Element* fNext; 327 | }; 328 | 329 | public: 330 | DoublyLinkedList() : fFirst(NULL), fLast(NULL) {} 331 | ~DoublyLinkedList() {} 332 | 333 | inline bool IsEmpty() const { return (fFirst == NULL); } 334 | 335 | inline void InsertBefore(Element* insertBefore, Element* element); 336 | inline void InsertAfter(Element* insertAfter, Element* element); 337 | inline void Insert(Element* element, bool back = true); 338 | inline void Add(Element* element, bool back = true); 339 | inline void Remove(Element* element); 340 | 341 | inline void Swap(Element* a, Element* b); 342 | 343 | inline void TakeFrom(DOUBLY_LINKED_LIST_CLASS_NAME* fromList); 344 | 345 | inline void RemoveAll(); 346 | inline void MakeEmpty() { RemoveAll(); } 347 | 348 | inline Element* First() const { return fFirst; } 349 | inline Element* Last() const { return fLast; } 350 | 351 | inline Element* Head() const { return fFirst; } 352 | inline Element* Tail() const { return fLast; } 353 | 354 | inline Element* RemoveHead(); 355 | inline Element* RemoveTail(); 356 | 357 | static inline Element* GetPrevious(Element* element); 358 | static inline Element* GetNext(Element* element); 359 | 360 | inline bool Contains(Element* element) const; 361 | // O(n)! 362 | 363 | inline int32 Count() const; 364 | // O(n)! 365 | 366 | template 367 | void Sort(const Less& less); 368 | // O(n^2) 369 | 370 | inline Iterator GetIterator() { return Iterator(this); } 371 | inline ConstIterator GetIterator() const { return ConstIterator(this); } 372 | 373 | inline ReverseIterator GetReverseIterator() 374 | { return ReverseIterator(this); } 375 | inline ConstReverseIterator GetReverseIterator() const 376 | { return ConstReverseIterator(this); } 377 | 378 | private: 379 | inline void Insert(Element* before, Element* element); 380 | // TODO: Obsolete! Use InsertBefore() instead! 381 | 382 | private: 383 | Element* fFirst; 384 | Element* fLast; 385 | 386 | static GetLink sGetLink; 387 | }; 388 | 389 | 390 | // inline methods 391 | 392 | // Insert 393 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 394 | void 395 | DOUBLY_LINKED_LIST_CLASS_NAME::Insert(Element* element, bool back) 396 | { 397 | if (element) { 398 | #if DEBUG_DOUBLY_LINKED_LIST 399 | ASSERT_PRINT(fFirst == NULL ? fLast == NULL : fLast != NULL, 400 | "list: %p\n", this); 401 | #endif 402 | 403 | Link* elLink = sGetLink(element); 404 | if (back) { 405 | // append 406 | elLink->previous = fLast; 407 | elLink->next = NULL; 408 | if (fLast) 409 | sGetLink(fLast)->next = element; 410 | else 411 | fFirst = element; 412 | fLast = element; 413 | } else { 414 | // prepend 415 | elLink->previous = NULL; 416 | elLink->next = fFirst; 417 | if (fFirst) 418 | sGetLink(fFirst)->previous = element; 419 | else 420 | fLast = element; 421 | fFirst = element; 422 | } 423 | } 424 | } 425 | 426 | 427 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 428 | void 429 | DOUBLY_LINKED_LIST_CLASS_NAME::InsertBefore(Element* before, Element* element) 430 | { 431 | ASSERT(element != NULL); 432 | 433 | if (before == NULL) { 434 | Insert(element); 435 | return; 436 | } 437 | 438 | #if DEBUG_DOUBLY_LINKED_LIST 439 | ASSERT_PRINT(fFirst == NULL ? fLast == NULL : fLast != NULL, 440 | "list: %p\n", this); 441 | #endif 442 | 443 | Link* beforeLink = sGetLink(before); 444 | Link* link = sGetLink(element); 445 | 446 | link->next = before; 447 | link->previous = beforeLink->previous; 448 | beforeLink->previous = element; 449 | 450 | if (link->previous != NULL) 451 | sGetLink(link->previous)->next = element; 452 | else 453 | fFirst = element; 454 | } 455 | 456 | 457 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 458 | void 459 | DOUBLY_LINKED_LIST_CLASS_NAME::InsertAfter(Element* after, Element* element) 460 | { 461 | ASSERT(element != NULL); 462 | 463 | if (after == NULL) { 464 | Insert(element, false); 465 | return; 466 | } 467 | 468 | #if DEBUG_DOUBLY_LINKED_LIST 469 | ASSERT_PRINT(fFirst == NULL ? fLast == NULL : fLast != NULL, 470 | "list: %p\n", this); 471 | #endif 472 | 473 | Link* afterLink = sGetLink(after); 474 | Link* link = sGetLink(element); 475 | 476 | link->previous = after; 477 | link->next = afterLink->next; 478 | afterLink->next = element; 479 | 480 | if (link->next != NULL) 481 | sGetLink(link->next)->previous = element; 482 | else 483 | fLast = element; 484 | } 485 | 486 | 487 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 488 | void 489 | DOUBLY_LINKED_LIST_CLASS_NAME::Insert(Element* before, Element* element) 490 | { 491 | InsertBefore(before, element); 492 | } 493 | 494 | 495 | // Add 496 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 497 | void 498 | DOUBLY_LINKED_LIST_CLASS_NAME::Add(Element* element, bool back) 499 | { 500 | Insert(element, back); 501 | } 502 | 503 | // Remove 504 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 505 | void 506 | DOUBLY_LINKED_LIST_CLASS_NAME::Remove(Element* element) 507 | { 508 | if (element == NULL) 509 | return; 510 | 511 | #if DEBUG_DOUBLY_LINKED_LIST 512 | ASSERT_PRINT(fFirst != NULL && fLast != NULL 513 | && (fFirst != fLast || element == fFirst), 514 | "list: %p, element: %p\n", this, element); 515 | #endif 516 | 517 | Link* elLink = sGetLink(element); 518 | 519 | if (element == fFirst) 520 | fFirst = elLink->next; 521 | else 522 | sGetLink(elLink->previous)->next = elLink->next; 523 | 524 | if (element == fLast) 525 | fLast = elLink->previous; 526 | else 527 | sGetLink(elLink->next)->previous = elLink->previous; 528 | 529 | elLink->next = elLink->previous = NULL; 530 | } 531 | 532 | // Swap 533 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 534 | void 535 | DOUBLY_LINKED_LIST_CLASS_NAME::Swap(Element* a, Element* b) 536 | { 537 | if (a && b && a != b) { 538 | Element* aNext = sGetLink(a)->next; 539 | Element* bNext = sGetLink(b)->next; 540 | if (a == bNext) { 541 | Remove(a); 542 | Insert(b, a); 543 | } else if (b == aNext) { 544 | Remove(b); 545 | Insert(a, b); 546 | } else { 547 | Remove(a); 548 | Remove(b); 549 | Insert(aNext, b); 550 | Insert(bNext, a); 551 | } 552 | } 553 | } 554 | 555 | // TakeFrom 556 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 557 | void 558 | DOUBLY_LINKED_LIST_CLASS_NAME::TakeFrom(DOUBLY_LINKED_LIST_CLASS_NAME* fromList) 559 | { 560 | if (fromList && fromList->fFirst) { 561 | if (fFirst) { 562 | sGetLink(fLast)->next = fromList->fFirst; 563 | sGetLink(fromList->fFirst)->previous = fLast; 564 | fLast = fromList->fLast; 565 | } else { 566 | fFirst = fromList->fFirst; 567 | fLast = fromList->fLast; 568 | } 569 | fromList->fFirst = NULL; 570 | fromList->fLast = NULL; 571 | } 572 | } 573 | 574 | // RemoveAll 575 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 576 | void 577 | DOUBLY_LINKED_LIST_CLASS_NAME::RemoveAll() 578 | { 579 | fFirst = NULL; 580 | fLast = NULL; 581 | } 582 | 583 | // RemoveHead 584 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 585 | Element* 586 | DOUBLY_LINKED_LIST_CLASS_NAME::RemoveHead() 587 | { 588 | Element* element = Head(); 589 | Remove(element); 590 | return element; 591 | } 592 | 593 | // RemoveTail 594 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 595 | Element* 596 | DOUBLY_LINKED_LIST_CLASS_NAME::RemoveTail() 597 | { 598 | Element* element = Tail(); 599 | Remove(element); 600 | return element; 601 | } 602 | 603 | // GetPrevious 604 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 605 | Element* 606 | DOUBLY_LINKED_LIST_CLASS_NAME::GetPrevious(Element* element) 607 | { 608 | Element* result = NULL; 609 | if (element) 610 | result = sGetLink(element)->previous; 611 | return result; 612 | } 613 | 614 | // GetNext 615 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 616 | Element* 617 | DOUBLY_LINKED_LIST_CLASS_NAME::GetNext(Element* element) 618 | { 619 | Element* result = NULL; 620 | if (element) 621 | result = sGetLink(element)->next; 622 | return result; 623 | } 624 | 625 | 626 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 627 | bool 628 | DOUBLY_LINKED_LIST_CLASS_NAME::Contains(Element* _element) const 629 | { 630 | for (Element* element = First(); element; element = GetNext(element)) { 631 | if (element == _element) 632 | return true; 633 | } 634 | 635 | return false; 636 | } 637 | 638 | 639 | // Count 640 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 641 | int32 642 | DOUBLY_LINKED_LIST_CLASS_NAME::Count() const 643 | { 644 | int32 count = 0; 645 | for (Element* element = First(); element; element = GetNext(element)) 646 | count++; 647 | return count; 648 | } 649 | 650 | 651 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 652 | template 653 | void 654 | DOUBLY_LINKED_LIST_CLASS_NAME::Sort(const Less& less) 655 | { 656 | // selection sort 657 | Element* tail = Head(); 658 | while (tail != NULL) { 659 | Element* leastElement = tail; 660 | Element* element = tail; 661 | while ((element = GetNext(element)) != NULL) { 662 | if (less(element, leastElement)) 663 | leastElement = element; 664 | } 665 | 666 | if (leastElement != tail) { 667 | Remove(leastElement); 668 | InsertBefore(tail, leastElement); 669 | } else 670 | tail = GetNext(tail); 671 | } 672 | } 673 | 674 | 675 | // sGetLink 676 | DOUBLY_LINKED_LIST_TEMPLATE_LIST 677 | GetLink DOUBLY_LINKED_LIST_CLASS_NAME::sGetLink; 678 | 679 | #endif /* __cplusplus */ 680 | 681 | #endif // _KERNEL_UTIL_DOUBLY_LINKED_LIST_H 682 | --------------------------------------------------------------------------------