diff --git a/Kernel/include/objects/message.h b/Kernel/include/objects/message.h index 0ced3629..3061ac24 100644 --- a/Kernel/include/objects/message.h +++ b/Kernel/include/objects/message.h @@ -10,42 +10,11 @@ #include -struct Message{ - union{ - uint64_t data; // Empty, pointer or integer - uint8_t* dataP; - }; - uint64_t id = 0; - uint16_t size = 0; -}; - -struct Reponse{ - Message* ret; - uint64_t id; -}; - struct MessageEndpointInfo{ uint16_t msgSize; }; class MessageEndpoint final : public KernelObject{ -private: - friend Pair,FancyRefPtr> CreatePair(); - uint16_t maxMessageSize = 8; - uint16_t messageQueueLimit = 128; - lock_t queueLock = 0; - - Semaphore queueAvailablilitySemaphore = Semaphore(messageQueueLimit); - - RingBuffer queue; - - FancyRefPtr peer; - - List waiting; - List> waitingResponse; - - lock_t waitingLock = 0; - lock_t waitingResponseLock = 0; public: static const uint16_t maxMessageSizeLimit = UINT16_MAX; @@ -71,11 +40,11 @@ class MessageEndpoint final : public KernelObject{ /// /// \param id Pointer to the ID to be populated /// \param size Pointer to the message size to be populated - /// \param data Pointer to an unsigned integer representing either 8 bytes of data (size <= 8) or a pointer to a buffer of size length containing message data + /// \param data Pointer to data /// /// \return 0 on success, 1 on empty, negative error code on failure ///////////////////////////// - int64_t Read(uint64_t* id, uint16_t* size, uint64_t* data); + int64_t Read(uint64_t* id, uint16_t* size, uint8_t* data); ///////////////////////////// /// \brief Send a message and return the response @@ -85,7 +54,7 @@ class MessageEndpoint final : public KernelObject{ /// /// \param id ID of the message to be sent /// \param size Size of the message to be sent - /// \param data Either a pointer to data (size > 8) or 8 bytes of data to be sent (size <= 8) + /// \param data Pointer to data /// /// \param rID ID of the expected message /// \param size Pointer to the message size to be populated @@ -95,7 +64,7 @@ class MessageEndpoint final : public KernelObject{ /// /// \return 0 on success, 1 on timeout, negative error code on failure ///////////////////////////// - int64_t Call(uint64_t id, uint16_t size, uint64_t data, uint64_t rID, uint16_t* rSize, uint64_t* rData, int64_t timeout); + int64_t Call(uint64_t id, uint16_t size, uint64_t data, uint64_t rID, uint16_t* rSize, uint8_t* rData, int64_t timeout); ///////////////////////////// /// \brief Send a message @@ -104,7 +73,7 @@ class MessageEndpoint final : public KernelObject{ /// /// \param id ID of the message to be sent /// \param size Size of the message to be sent - /// \param data Either a pointer to data (size > 8) or 8 bytes of data to be sent (size <= 8) + /// \param data Pointer to data /// /// \return 0 on success, negative error code on failure ///////////////////////////// @@ -124,4 +93,28 @@ class MessageEndpoint final : public KernelObject{ inline static constexpr kobject_id_t TypeID() { return KOBJECT_ID_MESSAGE_ENDPOINT; } inline kobject_id_t InstanceTypeID() const { return TypeID(); } + +private: + struct Response{ + uint64_t id; + uint16_t* size; + uint8_t** buffer; + }; + + friend Pair,FancyRefPtr> CreatePair(); + uint16_t maxMessageSize = 8; + uint16_t messageQueueLimit = 128; + lock_t queueLock = 0; + + Semaphore queueAvailablilitySemaphore = Semaphore(messageQueueLimit); + + RawRingBuffer queue; + + FancyRefPtr peer; + + List waiting; + List> waitingResponse; + + lock_t waitingLock = 0; + lock_t waitingResponseLock = 0; }; \ No newline at end of file diff --git a/Kernel/include/ringbuffer.h b/Kernel/include/ringbuffer.h index 2775c060..4f208bd4 100644 --- a/Kernel/include/ringbuffer.h +++ b/Kernel/include/ringbuffer.h @@ -4,7 +4,7 @@ #include #include -template +template class RingBuffer{ public: RingBuffer(){ @@ -17,9 +17,18 @@ class RingBuffer{ dequeuePointer = buffer; } - void Enqueue(T* data){ - acquireLock(&dequeueLock); + RingBuffer(unsigned bSize) : bufferSize(bSize) { + buffer = reinterpret_cast(kmalloc(sizeof(T) * bufferSize)); + + bufferEnd = &buffer[bufferSize]; + + enqueuePointer = buffer; + dequeuePointer = buffer; + } + + void Enqueue(const T* data){ acquireLock(&enqueueLock); + acquireLock(&dequeueLock); memcpy(enqueuePointer++, data, sizeof(T)); @@ -28,47 +37,141 @@ class RingBuffer{ } if(enqueuePointer == dequeuePointer){ + Resize((bufferSize + 2) << 1); + } - T* oldBuffer = buffer; - T* oldBufferEnd = bufferEnd; + releaseLock(&enqueueLock); + releaseLock(&dequeueLock); + } - bufferSize = (bufferSize + 2) << 1; + void EnqueueUnlocked(const T* data, size_t count){ + size_t contiguousCount = count; + size_t wrappedCount = 0; - buffer = reinterpret_cast(kmalloc(sizeof(T) * bufferSize)); - bufferEnd = &buffer[bufferSize - 1]; - - memcpy(bufferEnd - (oldBufferEnd - dequeuePointer), dequeuePointer, oldBufferEnd - dequeuePointer); + if(enqueuePointer < dequeuePointer && enqueuePointer + count > dequeuePointer){ + Resize((bufferSize << 1) + count); // Ring buffer is full + } else if(enqueuePointer + contiguousCount > bufferEnd){ + contiguousCount = (uintptr_t)(bufferEnd - enqueuePointer); // Get number of contiguous elements to copy + wrappedCount = count - contiguousCount; // Get number of elements that did not fit - dequeuePointer = bufferEnd - (oldBufferEnd - dequeuePointer); - enqueuePointer = buffer + (enqueuePointer - oldBuffer); + if(buffer + wrappedCount >= dequeuePointer){ + Resize((bufferSize << 1) + count); // Ring buffer is full + } + } - kfree(oldBuffer); + memcpy(enqueuePointer, data, sizeof(T) * contiguousCount); + + if(wrappedCount > 0){ + memcpy(buffer, data + contiguousCount, sizeof(T) * wrappedCount); } + + size += count; + enqueuePointer = buffer + ((enqueuePointer + count - buffer) % bufferSize); // Calculate new enqueuePointer + } + + inline void Enqueue(const T* data, size_t count){ + acquireLock(&enqueueLock); + acquireLock(&dequeueLock); + + EnqueueUnlocked(data, count); + releaseLock(&enqueueLock); releaseLock(&dequeueLock); } int Dequeue(T* data, size_t amount){ - acquireLock(&dequeueLock); if(dequeuePointer == enqueuePointer){ - releaseLock(&dequeueLock); return 0; } - size_t counter = 0; - while(dequeuePointer != enqueuePointer && counter < amount) { - memcpy(data++, dequeuePointer++, sizeof(T)); - counter++; + acquireLock(&dequeueLock); + + size_t contiguous = amount; + size_t wrapped = 0; + if(dequeuePointer < enqueuePointer && dequeuePointer + amount > enqueuePointer){ + contiguous = enqueuePointer - dequeuePointer; + } else if(dequeuePointer + contiguous > bufferEnd){ + contiguous = bufferEnd - dequeuePointer; + wrapped = amount - contiguous; + + if(buffer + wrapped > enqueuePointer){ + wrapped = enqueuePointer - buffer; + } + } + + memcpy(data, dequeuePointer, contiguous * sizeof(T)); + dequeuePointer += contiguous; + + if(dequeuePointer >= bufferEnd){ + dequeuePointer = buffer + wrapped; - if(dequeuePointer >= bufferEnd){ - dequeuePointer = buffer; + if(wrapped){ + memcpy(data + contiguous, buffer, wrapped * sizeof(T)); } } + + size -= contiguous + wrapped; releaseLock(&dequeueLock); - return counter; + return contiguous + wrapped; } -private: + + void Drain() { + acquireLock(&enqueueLock); + acquireLock(&dequeueLock); + + enqueuePointer = dequeuePointer = buffer; + size = 0; + + releaseLock(&enqueueLock); + releaseLock(&dequeueLock); + } + + void Drain(size_t count) { + acquireLock(&dequeueLock); + + if(dequeuePointer <= enqueuePointer && dequeuePointer + count > enqueuePointer){ + size = 0; + dequeuePointer = enqueuePointer; + } else if(dequeuePointer + count > bufferEnd){ + if(buffer + count > enqueuePointer){ + size = 0; + dequeuePointer = enqueuePointer; + } else { + dequeuePointer = buffer + count; + size -= count; + } + } else { + size -= count; + dequeuePointer += count; + } + + releaseLock(&dequeueLock); + } + + inline unsigned Count() { return size; } + inline bool Empty() { return dequeuePointer == enqueuePointer; } +protected: + void Resize(size_t size){ + T* oldBuffer = buffer; + T* oldBufferEnd = bufferEnd; + + bufferSize = size; + + buffer = reinterpret_cast(kmalloc(sizeof(T) * bufferSize)); + bufferEnd = &buffer[bufferSize]; + + memcpy(bufferEnd - (oldBufferEnd - dequeuePointer), dequeuePointer, (oldBufferEnd - dequeuePointer) * sizeof(T)); + if(dequeuePointer > enqueuePointer){ + memcpy(buffer, oldBuffer, (enqueuePointer - oldBuffer) * sizeof(T)); + } + + dequeuePointer = bufferEnd - (oldBufferEnd - dequeuePointer); + enqueuePointer = buffer + (enqueuePointer - oldBuffer); + + kfree(oldBuffer); + } + T* buffer = nullptr; T* bufferEnd = nullptr; size_t bufferSize = 0; @@ -76,6 +179,40 @@ class RingBuffer{ T* enqueuePointer = nullptr; T* dequeuePointer = nullptr; + unsigned size; + lock_t enqueueLock = 0; lock_t dequeueLock = 0; +}; + +class RawRingBuffer : public RingBuffer{ +public: + template + inline constexpr void EnqueueObjects(const T&... data){ + acquireLock(&enqueueLock); + acquireLock(&dequeueLock); + + EnqueueUnlocked(data...); + + releaseLock(&enqueueLock); + releaseLock(&dequeueLock); + } + +private: + template + inline constexpr void EnqueueUnlocked(const Pair& data){ + RingBuffer::EnqueueUnlocked(data.item1, data.item2 * sizeof(T)); + } + + template + inline constexpr void EnqueueUnlocked(const O& obj, const T&... data){ + EnqueueUnlocked(obj); + + EnqueueUnlocked(data...); + } + + template + inline constexpr void EnqueueUnlocked(const T& data){ + RingBuffer::EnqueueUnlocked(reinterpret_cast(&data), sizeof(T)); + } }; \ No newline at end of file diff --git a/Kernel/src/arch/x86_64/syscalls.cpp b/Kernel/src/arch/x86_64/syscalls.cpp index 56e8905e..7ab64338 100755 --- a/Kernel/src/arch/x86_64/syscalls.cpp +++ b/Kernel/src/arch/x86_64/syscalls.cpp @@ -2509,7 +2509,7 @@ long SysInterfaceConnect(RegisterContext* r){ /// \param endpoint (handle_id_t) Handle ID of specified endpoint /// \param id (uint64_t) Message ID /// \param size (uint64_t) Message Size -/// \param data (uint8_t*/uint64_t) Message data, if size <= 8 then treated as an integer containing message data, if size > 8 then treated as a pointer to message data +/// \param data (uint8_t*) Pointer to message data /// /// \return 0 on success, negative error code on failure ///////////////////////////// @@ -2519,6 +2519,8 @@ long SysEndpointQueue(RegisterContext* r){ Handle* endpHandle; if(Scheduler::FindHandle(currentProcess, SC_ARG0(r), &endpHandle)){ Log::Warning("(%s): SysEndpointQueue: Invalid handle ID %d", currentProcess->name, SC_ARG0(r)); + UserPrintStackTrace(r->rbp, Scheduler::GetCurrentProcess()->addressSpace); + return -EINVAL; } @@ -2528,7 +2530,7 @@ long SysEndpointQueue(RegisterContext* r){ } size_t size = SC_ARG2(r); - if(size > 8 && !Memory::CheckUsermodePointer(SC_ARG3(r), size, currentProcess->addressSpace)){ + if(!Memory::CheckUsermodePointer(SC_ARG3(r), size, currentProcess->addressSpace)){ return -EFAULT; // Data greater than 8 and invalid pointer } @@ -2577,7 +2579,7 @@ long SysEndpointDequeue(RegisterContext* r){ return -EFAULT; } - return endpoint->Read(reinterpret_cast(SC_ARG1(r)), reinterpret_cast(SC_ARG2(r)), reinterpret_cast(SC_ARG3(r))); + return endpoint->Read(reinterpret_cast(SC_ARG1(r)), reinterpret_cast(SC_ARG2(r)), reinterpret_cast(SC_ARG3(r))); } ///////////////////////////// @@ -2587,11 +2589,11 @@ long SysEndpointDequeue(RegisterContext* r){ /// /// \param endpoint (handle_id_t) Handle ID of specified endpoint /// \param id (uint64_t) id of message to send -/// \param data (uint8_t*/uint64_t) Message data to be sent, if size <= 8 then treated as an integer containing message data, if size > 8 then treated as a pointer to message data +/// \param data (uint8_t*) Message data to be sent /// \param rID (uint64_t) id of expected returned message /// \param rData (uint8_t*) Return message data buffer /// \param size (uint32_t*) Pointer containing size of message to be sent and size of returned message -/// \param timeout (uint64_t*) timeout in us +/// \param timeout (int64_t) timeout in us /// /// \return 0 on success, negative error code on failure ///////////////////////////// @@ -2610,13 +2612,13 @@ long SysEndpointCall(RegisterContext* r){ } uint16_t* size = reinterpret_cast(SC_ARG5(r)); - if((*size) > 8 && !Memory::CheckUsermodePointer(SC_ARG3(r), *size, currentProcess->addressSpace)){ - return -EFAULT; // Data greater than 8 and invalid pointer + if(!Memory::CheckUsermodePointer(SC_ARG3(r), *size, currentProcess->addressSpace)){ + return -EFAULT; // Size greater than 8 and invalid data pointer } MessageEndpoint* endpoint = reinterpret_cast(endpHandle->ko.get()); - return endpoint->Call(SC_ARG1(r), *size, SC_ARG2(r), SC_ARG3(r), size, reinterpret_cast(SC_ARG4(r)), -1); + return endpoint->Call(SC_ARG1(r), *size, SC_ARG2(r), SC_ARG3(r), size, reinterpret_cast(SC_ARG4(r)), -1); } ///////////////////////////// @@ -2640,12 +2642,12 @@ long SysEndpointInfo(RegisterContext* r){ Handle* endpHandle; if(Scheduler::FindHandle(currentProcess, SC_ARG0(r), &endpHandle)){ - Log::Warning("SysEndpointQueue: Invalid handle ID %d", SC_ARG0(r)); + Log::Warning("SysEndpointInfo: Invalid handle ID %d", SC_ARG0(r)); return -EINVAL; } if(!endpHandle->ko->IsType(MessageEndpoint::TypeID())){ - Log::Warning("SysEndpointQueue: Invalid handle type (ID %d)", SC_ARG0(r)); + Log::Warning("SysEndpointInfo: Invalid handle type (ID %d)", SC_ARG0(r)); return -EINVAL; } diff --git a/Kernel/src/objects/message.cpp b/Kernel/src/objects/message.cpp index 74da58fb..c5e2e9c4 100644 --- a/Kernel/src/objects/message.cpp +++ b/Kernel/src/objects/message.cpp @@ -24,58 +24,52 @@ MessageEndpoint::~MessageEndpoint(){ } void MessageEndpoint::Destroy(){ - Message m; - while(queue.Dequeue(&m, 1)){ - if(m.size > 8 && m.dataP){ - delete[] m.dataP; - } - } - if(peer.get()){ peer->peer = nullptr; } } -int64_t MessageEndpoint::Read(uint64_t* id, uint16_t* size, uint64_t* data){ +int64_t MessageEndpoint::Read(uint64_t* id, uint16_t* size, uint8_t* data){ assert(id); assert(size); assert(data); - Message m; - - acquireLock(&queueLock); - int r = queue.Dequeue(&m, 1); - releaseLock(&queueLock); - if(r < 1){ + if(queue.Empty()){ if(!peer.get()){ return -ENOTCONN; } + return 0; } - queueAvailablilitySemaphore.Signal(); + acquireLock(&queueLock); - *id = m.id; - *size = m.size; + queue.Dequeue(reinterpret_cast(id), sizeof(uint64_t)); + queue.Dequeue(reinterpret_cast(size), sizeof(uint16_t)); - if(m.size <= 8){ - *data = m.data; - } else { - memcpy(data, m.dataP, m.size); - } + if(*size){ + size_t read = queue.Dequeue(data, *size); + if(read < *size){ + Log::Warning("[MessageEndpoint] Draining message queue (expected %u bytes, only got %u)!", *size, read); + queue.Drain(); // Not all data has been written, drain the buffer - if(debugLevelMessageEndpoint >= DebugLevelVerbose){ - Log::Info("[MessageEndpoint] Receiving message (ID: %u, Size: %u)", m.id, m.size); + releaseLock(&queueLock); + return 0; + } } - if(m.size > 8 && m.dataP){ - delete[] m.dataP; + releaseLock(&queueLock); + + queueAvailablilitySemaphore.Signal(); + + if(debugLevelMessageEndpoint >= DebugLevelVerbose){ + Log::Info("[MessageEndpoint] Receiving message (ID: %u, Size: %u)", *id, *size); } return 1; } -int64_t MessageEndpoint::Call(uint64_t id, uint16_t size, uint64_t data, uint64_t rID, uint16_t* rSize, uint64_t* rData, int64_t timeout){ +int64_t MessageEndpoint::Call(uint64_t id, uint16_t size, uint64_t data, uint64_t rID, uint16_t* rSize, uint8_t* rData, int64_t timeout){ if(!peer.get()){ return -ENOTCONN; } @@ -88,31 +82,31 @@ int64_t MessageEndpoint::Call(uint64_t id, uint16_t size, uint64_t data, uint64_ assert(rData); Semaphore s = Semaphore(0); - Message m; - acquireLock(&waitingResponseLock); - waitingResponse.add_back({&s, {&m, rID}}); + + uint8_t* buffer = nullptr; + uint16_t returnSize; // We cannot use rSize as it lies within the process' address space, not the kernel's + waitingResponse.add_back({&s, {.id = rID, .size = &returnSize, .buffer = &buffer}}); + releaseLock(&waitingResponseLock); Write(id, size, data); // Send message // TODO: timeout - if(s.Wait()){ // Await reponse - return -EINTR; // Interrupted - } - - *rSize = m.size; + if(s.Wait()){ // Await response + if(buffer){ + delete buffer; + } - if(m.size <= 8){ - *rData = m.data; - } else { - memcpy(rData, m.dataP, m.size); + return -EINTR; // Interrupted } + + if(buffer){ + memcpy(rData, buffer, returnSize); + *rSize = returnSize; - if(m.size > 8){ - delete[] m.dataP; + delete buffer; } - return 0; } @@ -125,29 +119,23 @@ int64_t MessageEndpoint::Write(uint64_t id, uint16_t size, uint64_t data){ return -EINVAL; } - Message msg; - - msg.id = id; - msg.size = size; + acquireLock(&peer->waitingResponseLock); + for(auto it = peer->waitingResponse.begin(); it != peer->waitingResponse.end(); it++){ + if(it->item2.id == id){ + Response& response = it->item2; - if(msg.size <= 8){ - msg.data = data; - } else { - assert(data); + if(size){ + *it->item2.buffer = new uint8_t[size]; - msg.dataP = new uint8_t[maxMessageSize]; + memcpy(*it->item2.buffer, reinterpret_cast(data), size); + } - memcpy(msg.dataP, reinterpret_cast(data), size); - } + *response.size = size; - acquireLock(&peer->waitingResponseLock); - for(auto it = peer->waitingResponse.begin(); it != peer->waitingResponse.end(); it++){ - if(it->item2.id == id){ it->item1->Signal(); - *it->item2.ret = msg; if(debugLevelMessageEndpoint >= DebugLevelVerbose){ - Log::Info("[MessageEndpoint] Sending response (ID: %u, Size: %u) to peer", msg.id, msg.size); + Log::Info("[MessageEndpoint] Sending response (ID: %u, Size: %u) to peer", id, size); } peer->waitingResponse.remove(it); @@ -162,7 +150,11 @@ int64_t MessageEndpoint::Write(uint64_t id, uint16_t size, uint64_t data){ } acquireLock(&peer->queueLock); - peer->queue.Enqueue(&msg); + if(size) { + peer->queue.EnqueueObjects(id, size, Pair((uint8_t*)data, size)); + } else { + peer->queue.EnqueueObjects(id, size); + } acquireLock(&peer->waitingLock); while(peer->waiting.get_length() > 0){ @@ -171,7 +163,7 @@ int64_t MessageEndpoint::Write(uint64_t id, uint16_t size, uint64_t data){ releaseLock(&peer->waitingLock); if(debugLevelMessageEndpoint >= DebugLevelVerbose){ - Log::Info("[MessageEndpoint] Sending message (ID: %u, Size: %u) to peer", msg.id, msg.size); + Log::Info("[MessageEndpoint] Sending message (ID: %u, Size: %u) to peer", id, size); } releaseLock(&peer->queueLock); diff --git a/LibLemon/include/lemon/ipc/endpoint.h b/LibLemon/include/lemon/ipc/endpoint.h index feeb27a0..796b76e3 100644 --- a/LibLemon/include/lemon/ipc/endpoint.h +++ b/LibLemon/include/lemon/ipc/endpoint.h @@ -143,19 +143,19 @@ namespace Lemon{ return msgSize; } - inline long Queue(uint64_t id, uint8_t* data, uint16_t size) const{ + inline long Queue(uint64_t id, uint8_t* data, uint16_t size) const { return EndpointQueue(handle, id, size, reinterpret_cast(data)); } - inline long Queue(uint64_t id, uint64_t data, uint16_t size) const{ + inline long Queue(uint64_t id, uint64_t data, uint16_t size) const { return EndpointQueue(handle, id, size, data); } - inline long Queue(const Message& m) const{ - return EndpointQueue(handle, m.id(), m.length(), (m.length() > 8) ? reinterpret_cast(m.data()) : *(reinterpret_cast(m.data()))); + inline long Queue(const Message& m) const { + return EndpointQueue(handle, m.id(), m.length(), reinterpret_cast(m.data())); } - inline long Poll(Message& m) const{ + inline long Poll(Message& m) const { uint64_t id; uint16_t size; uint8_t* data = new uint8_t[msgSize]; @@ -173,7 +173,7 @@ namespace Lemon{ uint16_t size = call.length(); uint8_t* data = new uint8_t[msgSize]; - long ret = EndpointCall(handle, call.id(), (call.length() > 8) ? reinterpret_cast(call.data()) : *(reinterpret_cast(call.data())), id, reinterpret_cast(data), &size); + long ret = EndpointCall(handle, call.id(), reinterpret_cast(call.data()), id, reinterpret_cast(data), &size); if(!ret){ rmsg.Set(data, size, id); @@ -187,7 +187,7 @@ namespace Lemon{ uint16_t size = call.length(); uint8_t* data = const_cast(call.data()); - long ret = EndpointCall(handle, call.id(), (call.length() > 8) ? reinterpret_cast(call.data()) : *(reinterpret_cast(call.data())), id, reinterpret_cast(call.data()), &size); + long ret = EndpointCall(handle, call.id(), reinterpret_cast(call.data()), id, reinterpret_cast(call.data()), &size); if(!ret){ call.Set(data, size, id); diff --git a/LibLemon/include/lemon/ipc/interface.h b/LibLemon/include/lemon/ipc/interface.h index 8f2281ac..fef8773f 100755 --- a/LibLemon/include/lemon/ipc/interface.h +++ b/LibLemon/include/lemon/ipc/interface.h @@ -73,7 +73,7 @@ namespace Lemon{ /// \param m (const Message&) Message to send ///////////////////////////// inline long Queue(handle_t h, Message& m) const{ - return EndpointQueue(h, m.id(), m.length(), (m.length() > 8) ? reinterpret_cast(m.data()) : *(reinterpret_cast(m.data()))); + return EndpointQueue(h, m.id(), m.length(), reinterpret_cast(m.data())); } void RegisterObject(const std::string& name, int id); diff --git a/LibLemon/include/lemon/system/ipc.h b/LibLemon/include/lemon/system/ipc.h index 8ce0006b..a4b65ad6 100644 --- a/LibLemon/include/lemon/system/ipc.h +++ b/LibLemon/include/lemon/system/ipc.h @@ -70,7 +70,7 @@ namespace Lemon{ /// \param endpoint (handle_t) Handle ID of specified endpoint /// \param id (uint64_t) Message ID /// \param size (uint64_t) Message Size - /// \param data (uint8_t*/uint64_t) Message data, if size <= 8 then treated as an integer containing message data, if size > 8 then treated as a pointer to message data + /// \param data (uint8_t*) Message data /// /// \return 0 on success, negative error code on failure ///////////////////////////// @@ -101,7 +101,7 @@ namespace Lemon{ /// /// \param endpoint (handle_id_t) Handle ID of specified endpoint /// \param id (uint64_t) id of message to send - /// \param data (uint8_t*/uint64_t) Message data to be sent, if size <= 8 then treated as an integer containing message data, if size > 8 then treated as a pointer to message data + /// \param data (uint8_t*/uint64_t) Message data to be sent /// \param rID (uint64_t) id of expected returned message /// \param rData (uint8_t*) Return message data buffer /// \param size (uint32_t*) Pointer containing size of message to be sent and size of returned message diff --git a/System/LemonWM/lemonwm.h b/System/LemonWM/lemonwm.h index 661aae90..f0d885cf 100644 --- a/System/LemonWM/lemonwm.h +++ b/System/LemonWM/lemonwm.h @@ -79,7 +79,7 @@ class WMWindow : Lemon::Endpoint { void DrawClip(surface_t* surface, rect_t clip); //void Draw(surface_t* surface); - void PostEvent(Lemon::LemonEvent& ev) { Queue(Lemon::GUI::WindowEvent, reinterpret_cast(&ev), (uint16_t)sizeof(Lemon::LemonEvent)); } + void PostEvent(const Lemon::LemonEvent& ev) { Queue(Lemon::GUI::WindowEvent, reinterpret_cast(&ev), (uint16_t)sizeof(Lemon::LemonEvent)); } void Minimize(bool state); void Resize(vector2i_t size, int64_t bufferKey, WindowBuffer* bufferInfo); @@ -187,7 +187,7 @@ class WMInstance{ void* InitializeShellConnection(); void Poll(); - void PostEvent(Lemon::LemonEvent& ev, WMWindow* win); + void PostEvent(const Lemon::LemonEvent& ev, WMWindow* win); WMWindow* FindWindow(int id); void MinimizeWindow(WMWindow* win, bool state); diff --git a/System/LemonWM/wm.cpp b/System/LemonWM/wm.cpp index e231a8f2..9e53623e 100644 --- a/System/LemonWM/wm.cpp +++ b/System/LemonWM/wm.cpp @@ -60,13 +60,30 @@ void WMInstance::MinimizeWindow(int id, bool state){ } MinimizeWindow(win, state); + + if(lastMousedOver == win){ + Lemon::LemonEvent ev; + ev.event = Lemon::EventMouseExit; + + PostEvent(ev, win); + } } void WMInstance::SetActive(WMWindow* win){ if(active == win) return; - if(shellConnected && active && !(active->flags & WINDOW_FLAGS_NOSHELL) && !active->minimized){ - Lemon::Shell::SetWindowState(active->clientID, Lemon::Shell::ShellWindowStateNormal, shellClient); + if(active){ + if(shellConnected && !(active->flags & WINDOW_FLAGS_NOSHELL) && !active->minimized){ + Lemon::Shell::SetWindowState(active->clientID, Lemon::Shell::ShellWindowStateNormal, shellClient); + } + + if(active == lastMousedOver){ + Lemon::LemonEvent ev; + + ev.event = Lemon::EventMouseExit; + + PostEvent(ev, win); + } } active = win; @@ -323,7 +340,7 @@ void WMInstance::Poll(){ } } -void WMInstance::PostEvent(Lemon::LemonEvent& ev, WMWindow* win){ +void WMInstance::PostEvent(const Lemon::LemonEvent& ev, WMWindow* win){ win->PostEvent(ev); } @@ -497,23 +514,29 @@ void WMInstance::MouseMove(){ resizeStartPos = input.mouse.pos; } else { - if(lastMousedOver && !PointInWindowProper(lastMousedOver, input.mouse.pos)){ // Check if the last window moused over is still under the cursor - Lemon::LemonEvent ev; - ev.event = Lemon::EventMouseExit; + bool windowFound = false; + for(auto it = windows.rbegin(); it != windows.rend(); it++){ + WMWindow* win = *it; - PostEvent(ev, lastMousedOver); - - lastMousedOver = nullptr; // Set to null in case the mouse is not above any window - } + if(win->minimized){ + continue; + } - for(WMWindow* win : windows){ if(PointInWindowProper(win, input.mouse.pos)){ + windowFound = true; Lemon::LemonEvent ev; if(win == lastMousedOver){ ev.event = Lemon::EventMouseMoved; } else { ev.event = Lemon::EventMouseEnter; + + if(lastMousedOver){ + Lemon::LemonEvent ev; + ev.event = Lemon::EventMouseExit; + + PostEvent(ev, lastMousedOver); + } } ev.mousePos = input.mouse.pos - win->pos; @@ -523,10 +546,20 @@ void WMInstance::MouseMove(){ PostEvent(ev, win); lastMousedOver = win; // This window is now the last moused over - break; } } + + if(!windowFound){ // Check if the last window moused over is still under the cursor + if(lastMousedOver){ + Lemon::LemonEvent ev; + ev.event = Lemon::EventMouseExit; + + PostEvent(ev, lastMousedOver); + } + + lastMousedOver = nullptr; // Set to null in case the mouse is not above any window + } } }