From a7d16839941f7bb34820c2579aeaf48b7f4868f2 Mon Sep 17 00:00:00 2001
From: X512 <danger_mail@list.ru>
Date: Fri, 31 Dec 2021 08:17:23 +0900
Subject: Haiku: fix build and minimal operation

---
 dlls/nsiproxy.sys/ndis.c        | 10 ++++++++
 dlls/ntdll/unix/file.c          |  2 ++
 dlls/ntdll/unix/loader.c        |  4 +++
 dlls/ntdll/unix/serial.c        |  2 ++
 dlls/ntdll/unix/server.c        |  3 +++
 dlls/ntdll/unix/signal_x86_64.c | 45 +++++++++++++++++++++++++++++++++
 dlls/ntdll/unix/socket.c        |  7 +++++
 dlls/winex11.drv/bitblt.c       |  1 +
 dlls/ws2_32/unixlib.c           |  6 +++++
 server/change.c                 |  3 +++
 server/fd.c                     |  3 +++
 server/signal.c                 |  3 +++
 server/sock.c                   |  8 ++++++
 13 files changed, 97 insertions(+)

diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c
index 3e37bcecc78..ed8e206657b 100644
--- a/dlls/nsiproxy.sys/ndis.c
+++ b/dlls/nsiproxy.sys/ndis.c
@@ -264,6 +264,9 @@ static WCHAR *strdupAtoW( const char *str )
 
 static struct if_entry *add_entry( DWORD index, char *name )
 {
+#ifdef __HAIKU__
+    return NULL;
+#else
     struct if_entry *entry;
     int name_len = strlen( name );
 
@@ -292,6 +295,7 @@ static struct if_entry *add_entry( DWORD index, char *name )
 
     list_add_tail( &if_list, &entry->entry );
     return entry;
+#endif
 }
 
 static void update_if_table( void )
@@ -327,6 +331,7 @@ static void ifinfo_fill_dynamic( struct if_entry *entry, struct nsi_ndis_ifinfo_
     fd = socket( PF_INET, SOCK_DGRAM, 0 );
     if (fd == -1) return;
 
+#ifndef __HAIKU__
     if (!ioctl( fd, SIOCGIFFLAGS, &req ))
     {
         if (req.ifr_flags & IFF_UP) data->oper_status = IfOperStatusUp;
@@ -335,6 +340,7 @@ static void ifinfo_fill_dynamic( struct if_entry *entry, struct nsi_ndis_ifinfo_
 #endif
         else data->oper_status = IfOperStatusDown;
     } else data->oper_status = IfOperStatusUnknown;
+#endif
 
     data->flags.unk = 0;
     data->flags.not_media_conn = 0;
@@ -342,8 +348,12 @@ static void ifinfo_fill_dynamic( struct if_entry *entry, struct nsi_ndis_ifinfo_
     data->media_conn_state = MediaConnectStateConnected;
     data->unk = 0;
 
+#ifndef __HAIKU__
     if (!ioctl( fd, SIOCGIFMTU, &req )) data->mtu = req.ifr_mtu;
     else data->mtu = 0;
+#else
+    data->mtu = 0;
+#endif
 
     close( fd );
 
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 10d8f3de4a3..43e21056a0a 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -6529,6 +6529,7 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io
         }
 
         if (!get_mountmgr_fs_info( handle, fd, &drive, sizeof(drive) )) fs_type = drive.fs_type;
+#ifndef __HAIKU__
         else
         {
             struct statfs stfs;
@@ -6560,6 +6561,7 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io
 #endif
             }
         }
+#endif
 
         switch (fs_type)
         {
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 82d099de3be..a1e4515616f 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -870,7 +870,11 @@ static NTSTATUS map_so_dll( const IMAGE_NT_HEADERS *nt_descr, HMODULE module )
                   + sizeof(IMAGE_NT_HEADERS)
                   + nb_sections * sizeof(IMAGE_SECTION_HEADER));
 
+#ifdef __HAIKU__
+    mprotect(addr, size, PROT_READ | PROT_WRITE);
+#else
     if (anon_mmap_fixed( addr, size, PROT_READ | PROT_WRITE, 0 ) != addr) return STATUS_NO_MEMORY;
+#endif
 
     dos = (IMAGE_DOS_HEADER *)addr;
     nt  = (IMAGE_NT_HEADERS *)((BYTE *)(dos + 1) + sizeof(builtin_signature));
diff --git a/dlls/ntdll/unix/serial.c b/dlls/ntdll/unix/serial.c
index 83244d02d41..6d1d27c749e 100644
--- a/dlls/ntdll/unix/serial.c
+++ b/dlls/ntdll/unix/serial.c
@@ -280,9 +280,11 @@ static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
     switch (port.c_cflag & CSIZE)
     {
     case CS5:   slc->WordLength = 5;    break;
+#ifndef __HAIKU__
     case CS6:   slc->WordLength = 6;    break;
     case CS7:   slc->WordLength = 7;	break;
     case CS8:	slc->WordLength = 8;	break;
+#endif
     default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
     }
 
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 1dcd0792072..e6eb2c39a71 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -76,6 +76,9 @@
 #define _POSIX_SPAWN_DISABLE_ASLR 0x0100
 #endif
 #endif
+#ifdef __HAIKU__
+#define SIGIO SIGPOLL
+#endif
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 9e9a96db832..957f796444b 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -64,6 +64,11 @@
 #ifdef __APPLE__
 # include <mach/mach.h>
 #endif
+#ifdef __HAIKU__
+# include <SupportDefs.h>
+extern status_t		_kern_generic_syscall(const char *subsystem, uint32 function,
+						void *buffer, size_t bufferSize);
+#endif
 
 #define NONAMELESSUNION
 #define NONAMELESSSTRUCT
@@ -232,6 +237,34 @@ __ASM_GLOBAL_FUNC( alloc_fs_sel,
 #define FPU_sig(context)     ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw)
 #define XState_sig(context)  NULL
 
+#elif defined (__HAIKU__)
+
+#define RAX_sig(context)     ((context)->uc_mcontext.rax)
+#define RBX_sig(context)     ((context)->uc_mcontext.rbx)
+#define RCX_sig(context)     ((context)->uc_mcontext.rcx)
+#define RDX_sig(context)     ((context)->uc_mcontext.rdx)
+#define RSI_sig(context)     ((context)->uc_mcontext.rsi)
+#define RDI_sig(context)     ((context)->uc_mcontext.rdi)
+#define RBP_sig(context)     ((context)->uc_mcontext.rbp)
+#define R8_sig(context)      ((context)->uc_mcontext.r8)
+#define R9_sig(context)      ((context)->uc_mcontext.r9)
+#define R10_sig(context)     ((context)->uc_mcontext.r10)
+#define R11_sig(context)     ((context)->uc_mcontext.r11)
+#define R12_sig(context)     ((context)->uc_mcontext.r12)
+#define R13_sig(context)     ((context)->uc_mcontext.r13)
+#define R14_sig(context)     ((context)->uc_mcontext.r14)
+#define R15_sig(context)     ((context)->uc_mcontext.r15)
+#define CS_sig(context)      NULL
+#define FS_sig(context)      NULL
+#define GS_sig(context)      NULL
+#define EFL_sig(context)     ((context)->uc_mcontext.rflags)
+#define RIP_sig(context)     ((context)->uc_mcontext.rip)
+#define RSP_sig(context)     ((context)->uc_mcontext.rsp)
+#define TRAP_sig(context)    TRAP_x86_PAGEFLT
+#define ERROR_sig(context)   0
+#define FPU_sig(context)     ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext.fpu)
+#define XState_sig(context)  NULL
+
 #else
 #error You must define the signal context functions for your platform
 #endif
@@ -1511,10 +1544,12 @@ static inline void set_sigcontext( const CONTEXT *context, ucontext_t *sigcontex
     R14_sig(sigcontext) = context->R14;
     R15_sig(sigcontext) = context->R15;
     RIP_sig(sigcontext) = context->Rip;
+#ifndef __HAIKU__
     CS_sig(sigcontext)  = context->SegCs;
     FS_sig(sigcontext)  = context->SegFs;
     GS_sig(sigcontext)  = context->SegGs;
     EFL_sig(sigcontext) = context->EFlags;
+#endif
 #ifdef DS_sig
     DS_sig(sigcontext) = context->SegDs;
 #endif
@@ -2171,7 +2206,9 @@ static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec
         }
     }
 
+#ifndef __HAIKU__
     CS_sig(sigcontext)  = cs64_sel;
+#endif
     RIP_sig(sigcontext) = (ULONG_PTR)pKiUserExceptionDispatcher;
     RSP_sig(sigcontext) = (ULONG_PTR)stack;
     /* clear single-step, direction, and align check flag */
@@ -2550,6 +2587,12 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
     EXCEPTION_RECORD rec = { 0 };
     struct xcontext context;
     ucontext_t *ucontext = sigcontext;
+    printf("segv_handler\n");
+    printf("  IP: %#" PRIx64 "\n", RIP_sig(ucontext));
+    printf("  SP: %#" PRIx64 "\n", RSP_sig(ucontext));
+    printf("  FP: %#" PRIx64 "\n", RBP_sig(ucontext));
+    printf("  address: %#" PRIx64 "\n", siginfo->si_addr);
+    _exit(1);
 
     rec.ExceptionAddress = (void *)RIP_sig(ucontext);
     save_context( &context, sigcontext );
@@ -2911,6 +2954,8 @@ void signal_init_thread( TEB *teb )
        thread's gsbase.  Have each thread record its gsbase pointer into its
        TEB so alloc_tls_slot() can find it. */
     teb->Reserved5[0] = amd64_thread_data()->pthread_teb;
+#elif defined (__HAIKU__)
+    _kern_generic_syscall("thread", /*THREAD_SET_GS_BASE*/ 1, teb, 0);
 #else
 # error Please define setting %gs for your architecture
 #endif
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index 2e79b9baa0f..335b9fa8ed6 100644
--- a/dlls/ntdll/unix/socket.c
+++ b/dlls/ntdll/unix/socket.c
@@ -168,7 +168,9 @@ static NTSTATUS sock_errno_to_status( int err )
         case EDESTADDRREQ:      return STATUS_INVALID_PARAMETER;
         case EMSGSIZE:          return STATUS_BUFFER_OVERFLOW;
         case EPROTONOSUPPORT:
+#ifndef __HAIKU__
         case ESOCKTNOSUPPORT:
+#endif
         case EPFNOSUPPORT:
         case EAFNOSUPPORT:
         case EPROTOTYPE:        return STATUS_NOT_SUPPORTED;
@@ -1450,11 +1452,16 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
             }
             else
             {
+#ifdef __HAIKU__
+                status = sock_errno_to_status( -1 );
+                break;
+#else
                 if ((ret = ioctl( fd, SIOCATMARK, &value )) < 0)
                 {
                     status = sock_errno_to_status( errno );
                     break;
                 }
+#endif
                 /* windows is reversed with respect to unix */
                 *(int *)out_buffer = !value;
             }
diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c
index fad183b0b01..fe47611d8bf 100644
--- a/dlls/winex11.drv/bitblt.c
+++ b/dlls/winex11.drv/bitblt.c
@@ -41,6 +41,7 @@
 #  include <sys/ipc.h>
 # endif
 #endif
+#undef HAVE_LIBXXSHM
 
 #include "windef.h"
 #include "winbase.h"
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c
index 67edf06368e..4b9274bf867 100644
--- a/dlls/ws2_32/unixlib.c
+++ b/dlls/ws2_32/unixlib.c
@@ -166,7 +166,9 @@ static const int ip_protocol_map[][2] =
     MAP( IPPROTO_ICMP ),
     MAP( IPPROTO_IGMP ),
     MAP( IPPROTO_RAW ),
+#ifndef __HAIKU__
     {WS_IPPROTO_IPV4, IPPROTO_IPIP},
+#endif
 };
 
 #undef MAP
@@ -338,7 +340,9 @@ static unsigned int errno_from_unix( int err )
         case EPROTOTYPE:        return WSAEPROTOTYPE;
         case ENOPROTOOPT:       return WSAENOPROTOOPT;
         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
+#ifndef __HAIKU__
         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
+#endif
         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
@@ -354,7 +358,9 @@ static unsigned int errno_from_unix( int err )
         case EISCONN:           return WSAEISCONN;
         case ENOTCONN:          return WSAENOTCONN;
         case ESHUTDOWN:         return WSAESHUTDOWN;
+#ifndef __HAIKU__
         case ETOOMANYREFS:      return WSAETOOMANYREFS;
+#endif
         case ETIMEDOUT:         return WSAETIMEDOUT;
         case ECONNREFUSED:      return WSAECONNREFUSED;
         case ELOOP:             return WSAELOOP;
diff --git a/server/change.c b/server/change.c
index a01d6894151..a26f7d36214 100644
--- a/server/change.c
+++ b/server/change.c
@@ -36,6 +36,9 @@
 #ifdef HAVE_SYS_INOTIFY_H
 #include <sys/inotify.h>
 #endif
+#ifdef __HAIKU__
+#define SIGIO SIGPOLL
+#endif
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
diff --git a/server/fd.c b/server/fd.c
index c9a21186722..1a0840f4113 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -88,6 +88,9 @@
 #ifdef HAVE_SYS_SYSCALL_H
 #include <sys/syscall.h>
 #endif
+#ifdef __HAIKU__
+#undef ioctl
+#endif
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
diff --git a/server/signal.c b/server/signal.c
index 19b76d44c16..05dafe154f5 100644
--- a/server/signal.c
+++ b/server/signal.c
@@ -28,6 +28,9 @@
 #include <sys/resource.h>
 #endif
 #include <unistd.h>
+#ifdef __HAIKU__
+#define SIGIO SIGPOLL
+#endif
 
 #include "file.h"
 #include "object.h"
diff --git a/server/sock.c b/server/sock.c
index c9b71137c4c..daeb937bf4e 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -1483,7 +1483,9 @@ static int get_unix_protocol( int protocol )
         case WS_IPPROTO_ICMP: return IPPROTO_ICMP;
         case WS_IPPROTO_IGMP: return IPPROTO_IGMP;
         case WS_IPPROTO_IP: return IPPROTO_IP;
+#ifndef __HAIKU__
         case WS_IPPROTO_IPV4: return IPPROTO_IPIP;
+#endif
         case WS_IPPROTO_IPV6: return IPPROTO_IPV6;
         case WS_IPPROTO_RAW: return IPPROTO_RAW;
         case WS_IPPROTO_TCP: return IPPROTO_TCP;
@@ -1943,7 +1945,9 @@ static unsigned int sock_get_error( int err )
         case EPROTOTYPE:        return WSAEPROTOTYPE;
         case ENOPROTOOPT:       return WSAENOPROTOOPT;
         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
+#ifndef __HAIKU__
         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
+#endif
         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
@@ -1959,7 +1963,9 @@ static unsigned int sock_get_error( int err )
         case EISCONN:           return WSAEISCONN;
         case ENOTCONN:          return WSAENOTCONN;
         case ESHUTDOWN:         return WSAESHUTDOWN;
+#ifndef __HAIKU__
         case ETOOMANYREFS:      return WSAETOOMANYREFS;
+#endif
         case ETIMEDOUT:         return WSAETIMEDOUT;
         case ECONNREFUSED:      return WSAECONNREFUSED;
         case ELOOP:             return WSAELOOP;
@@ -2010,7 +2016,9 @@ static int sock_get_ntstatus( int err )
         case EDESTADDRREQ:      return STATUS_INVALID_PARAMETER;
         case EMSGSIZE:          return STATUS_BUFFER_OVERFLOW;
         case EPROTONOSUPPORT:
+#ifndef __HAIKU__
         case ESOCKTNOSUPPORT:
+#endif
         case EPFNOSUPPORT:
         case EAFNOSUPPORT:
         case EPROTOTYPE:        return STATUS_NOT_SUPPORTED;
-- 
2.30.2


From a598228f33d61990d18e09560d5028a018a22d91 Mon Sep 17 00:00:00 2001
From: X512 <danger_mail@list.ru>
Date: Sun, 16 Jan 2022 17:27:49 +0900
Subject: winehaiku.drv: add

---
 configure.ac                          |    1 +
 dlls/winehaiku.drv/Makefile.in        |   26 +
 dlls/winehaiku.drv/clipboard.c        |  105 ++
 dlls/winehaiku.drv/desktop.c          |   45 +
 dlls/winehaiku.drv/display.c          |   96 ++
 dlls/winehaiku.drv/gdi.c              |  163 +++
 dlls/winehaiku.drv/haikudrv.h         |  307 ++++++
 dlls/winehaiku.drv/haikudrv_main.c    |  109 ++
 dlls/winehaiku.drv/ime.c              |  181 ++++
 dlls/winehaiku.drv/init.c             |  103 ++
 dlls/winehaiku.drv/keyboard.c         |   92 ++
 dlls/winehaiku.drv/mouse.c            |   79 ++
 dlls/winehaiku.drv/settings.cpp       |   74 ++
 dlls/winehaiku.drv/systray.c          |   74 ++
 dlls/winehaiku.drv/version.rc         |   22 +
 dlls/winehaiku.drv/vidmode.c          |   57 +
 dlls/winehaiku.drv/vulkan.cpp         |  418 ++++++++
 dlls/winehaiku.drv/window.cpp         | 1393 +++++++++++++++++++++++++
 dlls/winehaiku.drv/winehaiku.drv.spec |   29 +
 dlls/winehaiku.drv/wintab.c           |   69 ++
 include/wine/server.h                 |    4 +-
 include/wine/vulkan_driver.h          |   40 +-
 include/winuser.h                     |    2 +-
 programs/explorer/desktop.c           |    2 +-
 24 files changed, 3467 insertions(+), 24 deletions(-)
 create mode 100644 dlls/winehaiku.drv/Makefile.in
 create mode 100644 dlls/winehaiku.drv/clipboard.c
 create mode 100644 dlls/winehaiku.drv/desktop.c
 create mode 100644 dlls/winehaiku.drv/display.c
 create mode 100644 dlls/winehaiku.drv/gdi.c
 create mode 100644 dlls/winehaiku.drv/haikudrv.h
 create mode 100644 dlls/winehaiku.drv/haikudrv_main.c
 create mode 100644 dlls/winehaiku.drv/ime.c
 create mode 100644 dlls/winehaiku.drv/init.c
 create mode 100644 dlls/winehaiku.drv/keyboard.c
 create mode 100644 dlls/winehaiku.drv/mouse.c
 create mode 100644 dlls/winehaiku.drv/settings.cpp
 create mode 100644 dlls/winehaiku.drv/systray.c
 create mode 100644 dlls/winehaiku.drv/version.rc
 create mode 100644 dlls/winehaiku.drv/vidmode.c
 create mode 100644 dlls/winehaiku.drv/vulkan.cpp
 create mode 100644 dlls/winehaiku.drv/window.cpp
 create mode 100644 dlls/winehaiku.drv/winehaiku.drv.spec
 create mode 100644 dlls/winehaiku.drv/wintab.c

diff --git a/configure.ac b/configure.ac
index 4fdb1ef33df..c7b4e40cf5e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3547,6 +3547,7 @@ WINE_CONFIG_MAKEFILE(dlls/winepulse.drv)
 WINE_CONFIG_MAKEFILE(dlls/wineusb.sys)
 WINE_CONFIG_MAKEFILE(dlls/winevulkan)
 WINE_CONFIG_MAKEFILE(dlls/winex11.drv)
+WINE_CONFIG_MAKEFILE(dlls/winehaiku.drv)
 WINE_CONFIG_MAKEFILE(dlls/winexinput.sys)
 WINE_CONFIG_MAKEFILE(dlls/wing.dll16,enable_win16)
 WINE_CONFIG_MAKEFILE(dlls/wing32)
diff --git a/dlls/winehaiku.drv/Makefile.in b/dlls/winehaiku.drv/Makefile.in
new file mode 100644
index 00000000000..0db76dd3a93
--- /dev/null
+++ b/dlls/winehaiku.drv/Makefile.in
@@ -0,0 +1,26 @@
+MODULE    = winehaiku.drv
+IMPORTS   = uuid setupapi rpcrt4 user32 gdi32 advapi32 win32u
+DELAYIMPORTS = comctl32 ole32 shell32 imm32
+EXTRAINCL = -I/boot/system/develop/headers/private/shared
+EXTRALIBS = -lbe -lstdc++ -lvulkan
+
+EXTRADLLFLAGS = -mcygwin
+
+C_SRCS = \
+	clipboard.c \
+	desktop.c \
+	display.c \
+	ime.c \
+	init.c \
+	keyboard.c \
+	mouse.c \
+	settings.cpp \
+	systray.c \
+	window.cpp \
+	wintab.c \
+	haikudrv_main.c \
+	vidmode.c \
+	gdi.c \
+	vulkan.cpp
+
+RC_SRCS = version.rc
diff --git a/dlls/winehaiku.drv/clipboard.c b/dlls/winehaiku.drv/clipboard.c
new file mode 100644
index 00000000000..8e840a543f1
--- /dev/null
+++ b/dlls/winehaiku.drv/clipboard.c
@@ -0,0 +1,105 @@
+/*
+ * X11 clipboard windows driver
+ *
+ * Copyright 1994 Martin Ayotte
+ * Copyright 1996 Alex Korobka
+ * Copyright 1999 Noel Borthwick
+ * Copyright 2003 Ulrich Czekalla for CodeWeavers
+ * Copyright 2014 Damjan Jovanovic
+ * Copyright 2016 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * NOTES:
+ *    This file contains the X specific implementation for the windows
+ *    Clipboard API.
+ *
+ *    Wine's internal clipboard is exposed to external apps via the X
+ *    selection mechanism.
+ *    Currently the driver asserts ownership via two selection atoms:
+ *    1. PRIMARY(XA_PRIMARY)
+ *    2. CLIPBOARD
+ *
+ *    In our implementation, the CLIPBOARD selection takes precedence over PRIMARY,
+ *    i.e. if a CLIPBOARD selection is available, it is used instead of PRIMARY.
+ *    When Wine takes ownership of the clipboard, it takes ownership of BOTH selections.
+ *    While giving up selection ownership, if the CLIPBOARD selection is lost,
+ *    it will lose both PRIMARY and CLIPBOARD and empty the clipboard.
+ *    However if only PRIMARY is lost, it will continue to hold the CLIPBOARD selection
+ *    (leaving the clipboard cache content unaffected).
+ *
+ *      Every format exposed via a windows clipboard format is also exposed through
+ *    a corresponding X selection target. A selection target atom is synthesized
+ *    whenever a new Windows clipboard format is registered via RegisterClipboardFormat,
+ *    or when a built-in format is used for the first time.
+ *    Windows native format are exposed by prefixing the format name with "<WCF>"
+ *    This allows us to uniquely identify windows native formats exposed by other
+ *    running WINE apps.
+ *
+ *      In order to allow external applications to query WINE for supported formats,
+ *    we respond to the "TARGETS" selection target. (See EVENT_SelectionRequest
+ *    for implementation) We use the same mechanism to query external clients for
+ *    availability of a particular format, by caching the list of available targets
+ *    by using the clipboard cache's "delayed render" mechanism. If a selection client
+ *    does not support the "TARGETS" selection target, we actually attempt to retrieve
+ *    the format requested as a fallback mechanism.
+ *
+ *      Certain Windows native formats are automatically converted to X native formats
+ *    and vice versa. If a native format is available in the selection, it takes
+ *    precedence, in order to avoid unnecessary conversions.
+ *
+ * FIXME: global format list needs a critical section
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <limits.h>
+#include <time.h>
+#include <assert.h>
+
+#include "haikudrv.h"
+
+#include "shlobj.h"
+#include "shellapi.h"
+#include "shlwapi.h"
+#include "wine/list.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
+
+
+/**************************************************************************
+ *		HAIKUDRV_UpdateClipboard
+ */
+void CDECL HAIKUDRV_UpdateClipboard(void)
+{
+}
+
+/**************************************************************************
+ *		HAIKUDRV_InitClipboard
+ */
+void HAIKUDRV_InitClipboard(void)
+{
+}
diff --git a/dlls/winehaiku.drv/desktop.c b/dlls/winehaiku.drv/desktop.c
new file mode 100644
index 00000000000..c06e22e65a3
--- /dev/null
+++ b/dlls/winehaiku.drv/desktop.c
@@ -0,0 +1,45 @@
+/*
+ * HAIKUDRV desktop window handling
+ *
+ * Copyright 2001 Alexandre Julliard
+ * Copyright 2020 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+
+#include "haikudrv.h"
+
+/* avoid conflict with field names in included win32 headers */
+#undef Status
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(haikudrv);
+
+
+/***********************************************************************
+ *		HAIKUDRV_create_desktop
+ *
+ * Create the X11 desktop window for the desktop mode.
+ */
+BOOL CDECL HAIKUDRV_create_desktop( UINT width, UINT height )
+{
+    return FALSE;
+}
diff --git a/dlls/winehaiku.drv/display.c b/dlls/winehaiku.drv/display.c
new file mode 100644
index 00000000000..d122ba270f2
--- /dev/null
+++ b/dlls/winehaiku.drv/display.c
@@ -0,0 +1,96 @@
+/*
+ * HAIKUDRV display device functions
+ *
+ * Copyright 2019 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "rpc.h"
+#include "winreg.h"
+#include "cfgmgr32.h"
+#include "initguid.h"
+#include "devguid.h"
+#include "devpkey.h"
+#include "ntddvdeo.h"
+#include "setupapi.h"
+#define WIN32_NO_STATUS
+#include "winternl.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "haikudrv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(haikudrv);
+
+
+void CDECL HAIKUDRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manager,
+                                        BOOL force, void *param )
+{
+    INT gpu_count, adapter_count, monitor_count;
+    DWORD len;
+    static BOOL called = FALSE;
+    
+    if (!called) {
+    	called = TRUE;
+    } else {
+        if (!force) return;
+    }
+
+    for (int i = 0; i < 1; i++)
+    {
+        struct gdi_gpu gdi_gpu =
+        {
+            .id = 1,
+            .vendor_id = 0x1002,
+            .device_id = 0x683f,
+            .subsys_id = 0,
+            .revision_id = 0,
+        };
+        const char *gpuName = "RADV VERDE";
+        RtlUTF8ToUnicodeN(gdi_gpu.name, sizeof(gdi_gpu.name), &len, gpuName, strlen(gpuName));
+        device_manager->add_gpu(&gdi_gpu, param);
+
+        for (int j = 0; j < 1; j++)
+        {
+            struct gdi_adapter gdi_adapter =
+            {
+                .id = 1,
+                .state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE,
+            };
+            device_manager->add_adapter( &gdi_adapter, param );
+
+            for (int k = 0; k < 1; k++)
+            {
+                struct gdi_monitor gdi_monitor =
+                {
+                    .rc_monitor = {0, 0, 1920, 1080},
+                    .rc_work = {0, 0, 1920, 1080},
+                    .state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE,
+                };
+                const char *monitorName = "Generic Non-PnP Monitor";
+                RtlUTF8ToUnicodeN(gdi_monitor.name, sizeof(gdi_monitor.name), &len,
+                                  monitorName, strlen(monitorName));
+                device_manager->add_monitor( &gdi_monitor, param );
+            }
+
+        }
+    }
+}
diff --git a/dlls/winehaiku.drv/gdi.c b/dlls/winehaiku.drv/gdi.c
new file mode 100644
index 00000000000..3bfc6bc9400
--- /dev/null
+++ b/dlls/winehaiku.drv/gdi.c
@@ -0,0 +1,163 @@
+#include "config.h"
+#include "haikudrv.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(haikudrv);
+
+
+typedef struct
+{
+    struct gdi_physdev  dev;
+} HAIKUDRV_PDEVICE;
+
+static inline HAIKUDRV_PDEVICE *get_haikudrv_dev(PHYSDEV dev)
+{
+    return (HAIKUDRV_PDEVICE*)dev;
+}
+
+
+/* a few dynamic device caps */
+static int horz_size;           /* horz. size of screen in millimeters */
+static int vert_size;           /* vert. size of screen in millimeters */
+static int bits_per_pixel;      /* pixel depth of screen */
+static int device_data_valid;   /* do the above variables have up-to-date values? */
+
+int retina_on = FALSE;
+
+static CRITICAL_SECTION device_data_section;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+    0, 0, &device_data_section,
+    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": device_data_section") }
+};
+static CRITICAL_SECTION device_data_section = { &critsect_debug, -1, 0, 0, 0, 0 };
+
+
+/**********************************************************************
+ *              device_init
+ *
+ * Perform initializations needed upon creation of the first device.
+ */
+static void device_init(void)
+{
+    /* Initialize device caps */
+    horz_size = 1920;
+    vert_size = 1080;
+
+    bits_per_pixel = 32;
+    device_data_valid = TRUE;
+}
+
+
+void haikudrv_reset_device_metrics(void)
+{
+    EnterCriticalSection(&device_data_section);
+    device_data_valid = FALSE;
+    LeaveCriticalSection(&device_data_section);
+}
+
+
+static HAIKUDRV_PDEVICE *create_haiku_physdev(void)
+{
+    HAIKUDRV_PDEVICE *physDev;
+ 
+    EnterCriticalSection(&device_data_section);
+    if (!device_data_valid) device_init();
+    LeaveCriticalSection(&device_data_section);
+
+    if (!(physDev = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev)))) return NULL;
+
+    return physDev;
+}
+
+
+/**********************************************************************
+ *              CreateDC (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_CreateDC(PHYSDEV *pdev, LPCWSTR device, LPCWSTR output,
+                                  const DEVMODEW* initData)
+{
+    HAIKUDRV_PDEVICE *physDev = create_haiku_physdev();
+
+    TRACE("pdev %p hdc %p device %s output %s initData %p\n", pdev,
+          (*pdev)->hdc, debugstr_w(device), debugstr_w(output), initData);
+
+    if (!physDev) return FALSE;
+
+    push_dc_driver(pdev, &physDev->dev, &haikudrv_funcs.dc_funcs);
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *              CreateCompatibleDC (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_CreateCompatibleDC(PHYSDEV orig, PHYSDEV *pdev)
+{
+    HAIKUDRV_PDEVICE *physDev = create_haiku_physdev();
+
+    TRACE("orig %p orig->hdc %p pdev %p pdev->hdc %p\n", orig, (orig ? orig->hdc : NULL), pdev,
+          ((pdev && *pdev) ? (*pdev)->hdc : NULL));
+
+    if (!physDev) return FALSE;
+
+    push_dc_driver(pdev, &physDev->dev, &haikudrv_funcs.dc_funcs);
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *              DeleteDC (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_DeleteDC(PHYSDEV dev)
+{
+    HAIKUDRV_PDEVICE *physDev = get_haikudrv_dev(dev);
+
+    TRACE("hdc %p\n", dev->hdc);
+
+    HeapFree(GetProcessHeap(), 0, physDev);
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *              GetDeviceCaps (HAIKUDRV.@)
+ */
+INT CDECL HAIKUDRV_GetDeviceCaps(PHYSDEV dev, INT cap)
+{
+    INT ret;
+
+    TRACE("hdc %p\n", dev->hdc);
+
+    EnterCriticalSection(&device_data_section);
+
+    if (!device_data_valid) device_init();
+
+    switch(cap)
+    {
+    case HORZSIZE:
+        ret = horz_size;
+        break;
+    case VERTSIZE:
+        ret = vert_size;
+        break;
+    case BITSPIXEL:
+        ret = bits_per_pixel;
+        break;
+    case HORZRES:
+    case VERTRES:
+    default:
+        LeaveCriticalSection(&device_data_section);
+        dev = GET_NEXT_PHYSDEV( dev, pGetDeviceCaps );
+        ret = dev->funcs->pGetDeviceCaps( dev, cap );
+        if ((cap == HORZRES || cap == VERTRES) && retina_on)
+            ret *= 2;
+        return ret;
+    }
+
+    TRACE("cap %d -> %d\n", cap, ret);
+
+    LeaveCriticalSection(&device_data_section);
+    return ret;
+}
diff --git a/dlls/winehaiku.drv/haikudrv.h b/dlls/winehaiku.drv/haikudrv.h
new file mode 100644
index 00000000000..65ffb414ab1
--- /dev/null
+++ b/dlls/winehaiku.drv/haikudrv.h
@@ -0,0 +1,307 @@
+/*
+ * X11 driver definitions
+ *
+ * Copyright 1996 Alexandre Julliard
+ * Copyright 1999 Patrik Stridvall
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_HAIKUDRV_H
+#define __WINE_HAIKUDRV_H
+
+#ifndef __WINE_CONFIG_H
+# error You must include config.h to use this header
+#endif
+
+#include <limits.h>
+
+#undef Status  /* avoid conflict with wintrnl.h */
+typedef int Status;
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "wine/gdi_driver.h"
+#include "wine/list.h"
+
+#define MAX_DASHLEN 16
+
+#define WINE_XDND_VERSION 5
+
+static inline void reset_bounds( RECT *bounds )
+{
+    bounds->left = bounds->top = INT_MAX;
+    bounds->right = bounds->bottom = INT_MIN;
+}
+
+static inline void add_bounds_rect( RECT *bounds, const RECT *rect )
+{
+    if (rect->left >= rect->right || rect->top >= rect->bottom) return;
+    bounds->left   = min( bounds->left, rect->left );
+    bounds->top    = min( bounds->top, rect->top );
+    bounds->right  = max( bounds->right, rect->right );
+    bounds->bottom = max( bounds->bottom, rect->bottom );
+}
+
+/* Wine driver X11 functions */
+
+extern BOOL CDECL HAIKUDRV_CreateDC(PHYSDEV *pdev, LPCWSTR device, LPCWSTR output, const DEVMODEW* initData);
+extern BOOL CDECL HAIKUDRV_CreateCompatibleDC(PHYSDEV orig, PHYSDEV *pdev);
+extern BOOL CDECL HAIKUDRV_DeleteDC(PHYSDEV dev);
+extern INT CDECL HAIKUDRV_GetDeviceCaps(PHYSDEV dev, INT cap);
+extern const struct vulkan_funcs *CDECL HAIKUDRV_wine_get_vulkan_driver(PHYSDEV dev, UINT version);
+
+extern BOOL CDECL HAIKUDRV_ActivateKeyboardLayout( HKL hkl, UINT flags ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_Beep(void) DECLSPEC_HIDDEN;
+extern INT CDECL HAIKUDRV_GetKeyNameText( LONG lparam, LPWSTR buffer, INT size ) DECLSPEC_HIDDEN;
+extern UINT CDECL HAIKUDRV_MapVirtualKeyEx( UINT code, UINT map_type, HKL hkl ) DECLSPEC_HIDDEN;
+extern INT CDECL HAIKUDRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
+                                     LPWSTR bufW, int bufW_size, UINT flags, HKL hkl ) DECLSPEC_HIDDEN;
+extern SHORT CDECL HAIKUDRV_VkKeyScanEx( WCHAR wChar, HKL hkl ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_DestroyCursorIcon( HCURSOR handle ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_SetCursorPos( INT x, INT y ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_GetCursorPos( LPPOINT pos ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_ClipCursor( LPCRECT clip ) DECLSPEC_HIDDEN;
+extern LONG CDECL HAIKUDRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
+                                                  HWND hwnd, DWORD flags, LPVOID lpvoid ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmode,
+                                                DWORD flags ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manager,
+                                               BOOL force, void *param ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_CreateDesktopWindow( HWND hwnd ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_CreateWindow( HWND hwnd ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_DestroyWindow( HWND hwnd ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_FlashWindowEx( PFLASHWINFO pfinfo ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_GetDC( HDC hdc, HWND hwnd, HWND top, const RECT *win_rect,
+                                const RECT *top_rect, DWORD flags ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_ReleaseDC( HWND hwnd, HDC hdc ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetCapture( HWND hwnd, UINT flags ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha,
+                                                     DWORD flags ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetParent( HWND hwnd, HWND parent, HWND old_parent ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetWindowIcon( HWND hwnd, UINT type, HICON icon ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetWindowText( HWND hwnd, LPCWSTR text ) DECLSPEC_HIDDEN;
+extern UINT CDECL HAIKUDRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) DECLSPEC_HIDDEN;
+extern LRESULT CDECL HAIKUDRV_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_UpdateClipboard(void) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
+                                              const RECT *window_rect ) DECLSPEC_HIDDEN;
+extern LRESULT CDECL HAIKUDRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
+                                            const RECT *window_rect, const RECT *client_rect, RECT *visible_rect,
+                                            struct window_surface **surface ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
+                                           const RECT *rectWindow, const RECT *rectClient,
+                                           const RECT *visible_rect, const RECT *valid_rects,
+                                           struct window_surface *surface ) DECLSPEC_HIDDEN;
+extern BOOL CDECL HAIKUDRV_SystemParametersInfo( UINT action, UINT int_param, void *ptr_param,
+                                               UINT flags ) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_ThreadDetach(void) DECLSPEC_HIDDEN;
+
+/* X11 driver internal functions */
+
+extern RGNDATA *HAIKUDRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp ) DECLSPEC_HIDDEN;
+
+/* IME support */
+extern void IME_SetOpenStatus(BOOL fOpen) DECLSPEC_HIDDEN;
+extern void IME_SetCompositionStatus(BOOL fOpen) DECLSPEC_HIDDEN;
+extern INT IME_GetCursorPos(void) DECLSPEC_HIDDEN;
+extern void IME_SetCursorPos(DWORD pos) DECLSPEC_HIDDEN;
+extern void IME_UpdateAssociation(HWND focus) DECLSPEC_HIDDEN;
+extern BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp,
+                                     DWORD dwCompLen, LPCVOID lpRead,
+                                     DWORD dwReadLen) DECLSPEC_HIDDEN;
+extern void IME_SetResultString(LPWSTR lpResult, DWORD dwResultlen) DECLSPEC_HIDDEN;
+
+
+/**************************************************************************
+ * X11 USER driver
+ */
+
+struct haikudrv_thread_data;
+
+extern struct haikudrv_thread_data *haikudrv_init_thread_data(void) DECLSPEC_HIDDEN;
+extern DWORD thread_data_tls_index DECLSPEC_HIDDEN;
+
+static inline struct haikudrv_thread_data *haikudrv_thread_data(void)
+{
+    DWORD err = GetLastError();  /* TlsGetValue always resets last error */
+    struct haikudrv_thread_data *data = (struct haikudrv_thread_data*)TlsGetValue( thread_data_tls_index );
+    SetLastError( err );
+    return data;
+}
+
+extern BOOL clipping_cursor DECLSPEC_HIDDEN;
+extern BOOL keyboard_grabbed DECLSPEC_HIDDEN;
+extern unsigned int screen_bpp DECLSPEC_HIDDEN;
+extern BOOL use_xkb DECLSPEC_HIDDEN;
+extern BOOL usexrandr DECLSPEC_HIDDEN;
+extern BOOL usexvidmode DECLSPEC_HIDDEN;
+extern BOOL ximInComposeMode DECLSPEC_HIDDEN;
+extern BOOL use_take_focus DECLSPEC_HIDDEN;
+extern BOOL use_primary_selection DECLSPEC_HIDDEN;
+extern BOOL use_system_cursors DECLSPEC_HIDDEN;
+extern BOOL show_systray DECLSPEC_HIDDEN;
+extern BOOL grab_pointer DECLSPEC_HIDDEN;
+extern BOOL grab_fullscreen DECLSPEC_HIDDEN;
+extern BOOL usexcomposite DECLSPEC_HIDDEN;
+extern BOOL managed_mode DECLSPEC_HIDDEN;
+extern BOOL decorated_mode DECLSPEC_HIDDEN;
+extern BOOL private_color_map DECLSPEC_HIDDEN;
+extern int primary_monitor DECLSPEC_HIDDEN;
+extern int copy_default_colors DECLSPEC_HIDDEN;
+extern int alloc_system_colors DECLSPEC_HIDDEN;
+extern int xrender_error_base DECLSPEC_HIDDEN;
+extern HMODULE haikudrv_module DECLSPEC_HIDDEN;
+extern char *process_name DECLSPEC_HIDDEN;
+
+/* X11 event driver */
+
+
+static inline void mirror_rect( const RECT *window_rect, RECT *rect )
+{
+    int width = window_rect->right - window_rect->left;
+    int tmp = rect->left;
+    rect->left = width - rect->right;
+    rect->right = width - tmp;
+}
+
+extern void HAIKUDRV_InitClipboard(void) DECLSPEC_HIDDEN;
+extern void CDECL HAIKUDRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN;
+extern DWORD CDECL HAIKUDRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout,
+                                                       DWORD mask, DWORD flags ) DECLSPEC_HIDDEN;
+
+#define DEPTH_COUNT 3
+extern const unsigned int *depths DECLSPEC_HIDDEN;
+
+/* Required functions for changing and enumerating display settings */
+struct haikudrv_settings_handler
+{
+    /* A name to tell what host driver is used */
+    const char *name;
+
+    /* Higher priority can override handlers with a lower priority */
+    UINT priority;
+
+    /* get_id() will be called to map a device name, e.g., \\.\DISPLAY1 to a driver specific id.
+     * Following functions use this id to identify the device.
+     *
+     * Return FALSE if the device cannot be found and TRUE on success */
+    BOOL (*get_id)(const WCHAR *device_name, ULONG_PTR *id);
+
+    /* get_modes() will be called to get a list of supported modes of the device of id in modes
+     * with respect to flags, which could be 0, EDS_RAWMODE or EDS_ROTATEDMODE. If the implementation
+     * uses dmDriverExtra then every DEVMODEW in the list must have the same dmDriverExtra value
+     *
+     * Following fields in DEVMODE must be valid:
+     * dmSize, dmDriverExtra, dmFields, dmDisplayOrientation, dmBitsPerPel, dmPelsWidth, dmPelsHeight,
+     * dmDisplayFlags and dmDisplayFrequency
+     *
+     * Return FALSE on failure with parameters unchanged and error code set. Return TRUE on success */
+    BOOL (*get_modes)(ULONG_PTR id, DWORD flags, DEVMODEW **modes, UINT *mode_count);
+
+    /* free_modes() will be called to free the mode list returned from get_modes() */
+    void (*free_modes)(DEVMODEW *modes);
+
+    /* get_current_mode() will be called to get the current display mode of the device of id
+     *
+     * Following fields in DEVMODE must be valid:
+     * dmFields, dmDisplayOrientation, dmBitsPerPel, dmPelsWidth, dmPelsHeight, dmDisplayFlags,
+     * dmDisplayFrequency and dmPosition
+     *
+     * Return FALSE on failure with parameters unchanged and error code set. Return TRUE on success */
+    BOOL (*get_current_mode)(ULONG_PTR id, DEVMODEW *mode);
+
+    /* set_current_mode() will be called to change the display mode of the display device of id.
+     * mode must be a valid mode from get_modes() with optional fields, such as dmPosition set.
+     *
+     * Return DISP_CHANGE_*, same as ChangeDisplaySettingsExW() return values */
+    LONG (*set_current_mode)(ULONG_PTR id, DEVMODEW *mode);
+};
+
+extern void HAIKUDRV_Settings_SetHandler(const struct haikudrv_settings_handler *handler) DECLSPEC_HIDDEN;
+
+extern void HAIKUDRV_resize_desktop(BOOL) DECLSPEC_HIDDEN;
+void HAIKUDRV_Settings_Init(void) DECLSPEC_HIDDEN;
+
+void HAIKUDRV_XF86VM_Init(void) DECLSPEC_HIDDEN;
+void HAIKUDRV_XRandR_Init(void) DECLSPEC_HIDDEN;
+void init_user_driver(void) DECLSPEC_HIDDEN;
+
+/* X11 display device handler. Used to initialize display device registry data */
+
+/* Required functions for display device registry initialization */
+struct haikudrv_display_device_handler
+{
+    /* A name to tell what host driver is used */
+    const char *name;
+
+    /* Higher priority can override handlers with lower priority */
+    INT priority;
+
+    /* get_gpus will be called to get a list of GPUs. First GPU has to be where the primary adapter is.
+     *
+     * Return FALSE on failure with parameters unchanged */
+    BOOL (*get_gpus)(struct gdi_gpu **gpus, int *count);
+
+    /* get_adapters will be called to get a list of adapters in EnumDisplayDevices context under a GPU.
+     * The first adapter has to be primary if GPU is primary.
+     *
+     * Return FALSE on failure with parameters unchanged */
+    BOOL (*get_adapters)(ULONG_PTR gpu_id, struct gdi_adapter **adapters, int *count);
+
+    /* get_monitors will be called to get a list of monitors in EnumDisplayDevices context under an adapter.
+     * The first monitor has to be primary if adapter is primary.
+     *
+     * Return FALSE on failure with parameters unchanged */
+    BOOL (*get_monitors)(ULONG_PTR adapter_id, struct gdi_monitor **monitors, int *count);
+
+    /* free_gpus will be called to free a GPU list from get_gpus */
+    void (*free_gpus)(struct gdi_gpu *gpus);
+
+    /* free_adapters will be called to free an adapter list from get_adapters */
+    void (*free_adapters)(struct gdi_adapter *adapters);
+
+    /* free_monitors will be called to free a monitor list from get_monitors */
+    void (*free_monitors)(struct gdi_monitor *monitors, int count);
+
+    /* register_event_handlers will be called to register event handlers.
+     * This function pointer is optional and can be NULL when driver doesn't support it */
+    void (*register_event_handlers)(void);
+};
+
+extern HANDLE get_display_device_init_mutex(void) DECLSPEC_HIDDEN;
+extern BOOL get_host_primary_gpu(struct gdi_gpu *gpu) DECLSPEC_HIDDEN;
+extern void release_display_device_init_mutex(HANDLE) DECLSPEC_HIDDEN;
+extern void HAIKUDRV_DisplayDevices_SetHandler(const struct haikudrv_display_device_handler *handler) DECLSPEC_HIDDEN;
+extern void HAIKUDRV_DisplayDevices_Init(BOOL force) DECLSPEC_HIDDEN;
+extern void HAIKUDRV_DisplayDevices_RegisterEventHandlers(void) DECLSPEC_HIDDEN;
+extern void HAIKUDRV_DisplayDevices_Update(BOOL) DECLSPEC_HIDDEN;
+/* Display device handler used in virtual desktop mode */
+extern struct haikudrv_display_device_handler desktop_handler DECLSPEC_HIDDEN;
+
+
+extern const struct user_driver_funcs haikudrv_funcs;
+
+
+extern BOOL HaikuStartApplication(void);
+
+#endif  /* __WINE_HAIKUDRV_H */
diff --git a/dlls/winehaiku.drv/haikudrv_main.c b/dlls/winehaiku.drv/haikudrv_main.c
new file mode 100644
index 00000000000..031f6d95a76
--- /dev/null
+++ b/dlls/winehaiku.drv/haikudrv_main.c
@@ -0,0 +1,109 @@
+/*
+ * HAIKUDRV initialization code
+ *
+ * Copyright 1998 Patrik Stridvall
+ * Copyright 2000 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+
+#include "haikudrv.h"
+#include "wine/server.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "wine/list.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(haikudrv);
+WINE_DECLARE_DEBUG_CHANNEL(synchronous);
+WINE_DECLARE_DEBUG_CHANNEL(winediag);
+
+DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
+
+
+/***********************************************************************
+ *           HAIKUDRV process initialisation routine
+ */
+static BOOL process_attach(void)
+{
+    if (!HaikuStartApplication()) return FALSE;
+    if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
+    init_user_driver();
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           HAIKUDRV initialisation routine
+ */
+BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
+{
+    BOOL ret = TRUE;
+
+    switch(reason)
+    {
+    case DLL_PROCESS_ATTACH:
+        DisableThreadLibraryCalls( hinst );
+        ret = process_attach();
+        break;
+    }
+    return ret;
+}
+
+
+/***********************************************************************
+ *              SystemParametersInfo (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_SystemParametersInfo( UINT action, UINT int_param, void *ptr_param, UINT flags )
+{
+    return FALSE;  /* let user32 handle it */
+}
+
+/**********************************************************************
+ *           HAIKUDRV_D3DKMTSetVidPnSourceOwner
+ */
+NTSTATUS CDECL HAIKUDRV_D3DKMTSetVidPnSourceOwner( const D3DKMT_SETVIDPNSOURCEOWNER *desc )
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    return status;
+}
+
+/**********************************************************************
+ *           HAIKUDRV_D3DKMTCheckVidPnExclusiveOwnership
+ */
+NTSTATUS CDECL HAIKUDRV_D3DKMTCheckVidPnExclusiveOwnership( const D3DKMT_CHECKVIDPNEXCLUSIVEOWNERSHIP *desc )
+{
+    return STATUS_SUCCESS;
+}
diff --git a/dlls/winehaiku.drv/ime.c b/dlls/winehaiku.drv/ime.c
new file mode 100644
index 00000000000..beb8d7c29e3
--- /dev/null
+++ b/dlls/winehaiku.drv/ime.c
@@ -0,0 +1,181 @@
+/*
+ * The IME for interfacing with XIM
+ *
+ * Copyright 2008 CodeWeavers, Aric Stewart
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * Notes:
+ *  The normal flow for IMM/IME Processing is as follows.
+ * 1) The Keyboard Driver generates key messages which are first passed to
+ *    the IMM and then to IME via ImeProcessKey. If the IME returns 0  then
+ *    it does not want the key and the keyboard driver then generates the
+ *    WM_KEYUP/WM_KEYDOWN messages.  However if the IME is going to process the
+ *    key it returns non-zero.
+ * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to
+ *    process the key.  the IME modifies the HIMC structure to reflect the
+ *    current state and generates any messages it needs the IMM to process.
+ * 3) IMM checks the messages and send them to the application in question. From
+ *    here the IMM level deals with if the application is IME aware or not.
+ *
+ *  This flow does not work well for the X11 driver and XIM.
+ *   (It works fine for Mac)
+ *  As such we will have to reroute step 1.  Instead the haikudrv driver will
+ *  generate an XIM events and call directly into this IME implementation.
+ *  As such we will have to use the alternative ImmGenerateMessage path to be
+ *  generate the messages that we want the IMM layer to send to the application.
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "imm.h"
+#include "ddk/imm.h"
+#include "winnls.h"
+#include "haikudrv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(imm);
+
+
+BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass,
+                       LPCWSTR lpszOption)
+{
+    return TRUE;
+}
+
+BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData)
+{
+    FIXME("(%p, %p, %d, %p): stub\n", hKL, hWnd, dwMode, lpData);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource,
+                LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag)
+
+{
+    FIXME("(%p, %s, %p, %d, %d): stub\n", hIMC, debugstr_w(lpSource),
+                                          lpCandList, dwBufLen, uFlag);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+BOOL WINAPI ImeDestroy(UINT uForce)
+{
+    return TRUE;
+}
+
+LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData)
+{
+    FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState)
+{
+    /* See the comment at the head of this file */
+    TRACE("We do no processing via this route\n");
+    return FALSE;
+}
+
+BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect)
+{
+    return TRUE;
+}
+
+BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag)
+{
+    static int once;
+
+    if (!once++)
+        FIXME("(%p, %x): stub\n", hIMC, fFlag);
+    return TRUE;
+}
+
+UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState,
+                          LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC)
+{
+    /* See the comment at the head of this file */
+    TRACE("We do no processing via this route\n");
+    return 0;
+}
+
+BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
+{
+    return FALSE;
+}
+
+BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle,
+                            LPCWSTR lpszRegister)
+{
+    FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
+                                  debugstr_w(lpszRegister));
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle,
+                              LPCWSTR lpszUnregister)
+{
+    FIXME("(%s, %d, %s): stub\n", debugstr_w(lpszReading), dwStyle,
+                                  debugstr_w(lpszUnregister));
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf)
+{
+    FIXME("(%d, %p): stub\n", nItem, lpStyleBuf);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc,
+                                LPCWSTR lpszReading, DWORD dwStyle,
+                                LPCWSTR lpszRegister, LPVOID lpData)
+{
+    FIXME("(%p, %s, %d, %s, %p): stub\n", lpfnEnumProc,
+            debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister),
+            lpData);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp,
+                                    DWORD dwCompLen, LPCVOID lpRead,
+                                    DWORD dwReadLen)
+{
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC,  DWORD dwFlags,  DWORD dwType,
+            LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu,
+            DWORD dwSize)
+{
+    FIXME("(%p, %x %x %p %p %x): stub\n", hIMC, dwFlags, dwType,
+                                lpImeParentMenu, lpImeMenu, dwSize);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
diff --git a/dlls/winehaiku.drv/init.c b/dlls/winehaiku.drv/init.c
new file mode 100644
index 00000000000..a0a279b9837
--- /dev/null
+++ b/dlls/winehaiku.drv/init.c
@@ -0,0 +1,103 @@
+/*
+ * Haiku graphics driver initialisation functions
+ *
+ * Copyright 1996 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "haikudrv.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(haikudrv);
+
+
+#define GDI_HOOK(name) .dc_funcs.p##name = HAIKUDRV_##name
+#define GDI_WINE_HOOK(name) .dc_funcs.name = HAIKUDRV_##name
+#define USER_HOOK(name) .p##name = HAIKUDRV_##name
+const struct user_driver_funcs haikudrv_funcs =
+{
+    GDI_HOOK(CreateCompatibleDC),
+    GDI_HOOK(CreateDC),
+    GDI_HOOK(DeleteDC),
+    GDI_HOOK(GetDeviceCaps),
+//  GDI_HOOK(GetDeviceGammaRamp),
+//  GDI_HOOK(SetDeviceGammaRamp),
+//  GDI_WINE_HOOK(wine_get_wgl_driver),
+    GDI_WINE_HOOK(wine_get_vulkan_driver),
+    .dc_funcs.priority = GDI_PRIORITY_GRAPHICS_DRV,
+
+    /* keyboard functions */
+    USER_HOOK(ActivateKeyboardLayout),
+    USER_HOOK(Beep),
+    USER_HOOK(GetKeyNameText),
+    USER_HOOK(MapVirtualKeyEx),
+    USER_HOOK(ToUnicodeEx),
+    USER_HOOK(VkKeyScanEx),
+
+    /* cursor/icon functions */
+    USER_HOOK(DestroyCursorIcon),
+    USER_HOOK(SetCursor),
+    USER_HOOK(GetCursorPos),
+    USER_HOOK(SetCursorPos),
+    USER_HOOK(ClipCursor),
+
+    /* clipboard functions */
+    USER_HOOK(UpdateClipboard),
+
+    /* display modes */
+    USER_HOOK(ChangeDisplaySettingsEx),
+    USER_HOOK(EnumDisplaySettingsEx),
+    USER_HOOK(UpdateDisplayDevices),
+
+    /* windowing functions */
+    USER_HOOK(CreateDesktopWindow),
+    USER_HOOK(CreateWindow),
+    USER_HOOK(DestroyWindow),
+    USER_HOOK(FlashWindowEx),
+//  USER_HOOK(GetDC),
+//  USER_HOOK(MsgWaitForMultipleObjectsEx),
+//  USER_HOOK(ReleaseDC),
+//  USER_HOOK(ScrollDC),
+    USER_HOOK(SetCapture),
+    USER_HOOK(SetFocus),
+    USER_HOOK(SetLayeredWindowAttributes),
+    USER_HOOK(SetParent),
+    USER_HOOK(SetWindowIcon),
+    USER_HOOK(SetWindowRgn),
+    USER_HOOK(SetWindowStyle),
+    USER_HOOK(SetWindowText),
+    USER_HOOK(ShowWindow),
+    USER_HOOK(SysCommand),
+    USER_HOOK(UpdateLayeredWindow),
+    USER_HOOK(WindowMessage),
+    USER_HOOK(WindowPosChanging),
+    USER_HOOK(WindowPosChanged),
+
+    /* system parameters */
+    USER_HOOK(SystemParametersInfo),
+
+    /* thread management */
+    USER_HOOK(ThreadDetach),
+};
+#undef GDI_HOOK
+#undef GDI_WINE_HOOK
+#undef USER_HOOK
+
+void init_user_driver(void)
+{
+    __wine_set_user_driver(&haikudrv_funcs, WINE_GDI_DRIVER_VERSION);
+}
diff --git a/dlls/winehaiku.drv/keyboard.c b/dlls/winehaiku.drv/keyboard.c
new file mode 100644
index 00000000000..007004f4924
--- /dev/null
+++ b/dlls/winehaiku.drv/keyboard.c
@@ -0,0 +1,92 @@
+/*
+ * X11 keyboard driver
+ *
+ * Copyright 1993 Bob Amstadt
+ * Copyright 1996 Albrecht Kleine
+ * Copyright 1997 David Faure
+ * Copyright 1998 Morten Welinder
+ * Copyright 1998 Ulrich Weigand
+ * Copyright 1999 Ove Kåven
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define NONAMELESSUNION
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "ime.h"
+#include "haikudrv.h"
+#include "wine/server.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
+WINE_DECLARE_DEBUG_CHANNEL(key);
+
+
+/***********************************************************************
+ *		ActivateKeyboardLayout (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
+{
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *		VkKeyScanEx (HAIKUDRV.@)
+ *
+ * Note: Windows ignores HKL parameter and uses current active layout instead
+ */
+SHORT CDECL HAIKUDRV_VkKeyScanEx(WCHAR wChar, HKL hkl)
+{
+    //FIXME("(%u): stub\n", wChar);
+    return 0;
+}
+
+/***********************************************************************
+ *		MapVirtualKeyEx (HAIKUDRV.@)
+ */
+UINT CDECL HAIKUDRV_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl)
+{
+    //FIXME("(%u): stub\n", wCode);
+    return 0;
+}
+
+/***********************************************************************
+ *		GetKeyNameText (HAIKUDRV.@)
+ */
+INT CDECL HAIKUDRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
+{
+  return 0;
+}
+
+/***********************************************************************
+ *		Beep (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_Beep(void)
+{
+}
diff --git a/dlls/winehaiku.drv/mouse.c b/dlls/winehaiku.drv/mouse.c
new file mode 100644
index 00000000000..b44039e9d76
--- /dev/null
+++ b/dlls/winehaiku.drv/mouse.c
@@ -0,0 +1,79 @@
+/*
+ * X11 mouse driver
+ *
+ * Copyright 1998 Ulrich Weigand
+ * Copyright 2007 Henri Verbeet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+
+
+#define NONAMELESSUNION
+#define OEMRESOURCE
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+
+#include "haikudrv.h"
+#include "wine/server.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(cursor);
+
+
+/***********************************************************************
+ *		DestroyCursorIcon (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_DestroyCursorIcon( HCURSOR handle )
+{
+}
+
+/***********************************************************************
+ *		SetCursor (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_SetCursor( HCURSOR handle )
+{
+}
+
+/***********************************************************************
+ *		SetCursorPos (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_SetCursorPos( INT x, INT y )
+{
+    return TRUE;
+}
+
+/***********************************************************************
+ *		GetCursorPos (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_GetCursorPos(LPPOINT pos)
+{
+    return TRUE;
+}
+
+/***********************************************************************
+ *		ClipCursor (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_ClipCursor( LPCRECT clip )
+{
+    return TRUE;
+}
diff --git a/dlls/winehaiku.drv/settings.cpp b/dlls/winehaiku.drv/settings.cpp
new file mode 100644
index 00000000000..967ae928b6f
--- /dev/null
+++ b/dlls/winehaiku.drv/settings.cpp
@@ -0,0 +1,74 @@
+/*
+ * Wine X11drv display settings functions
+ *
+ * Copyright 2003 Alexander James Pasadyn
+ * Copyright 2020 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include <stdlib.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+extern "C" {
+#include "haikudrv.h"
+
+#include "windef.h"
+#include "winreg.h"
+#include "wingdi.h"
+#include "wine/debug.h"
+#include "wine/heap.h"
+#include "wine/unicode.h"
+}
+
+WINE_DEFAULT_DEBUG_CHANNEL(x11settings);
+
+
+/***********************************************************************
+ *		EnumDisplaySettingsEx  (HAIKUDRV.@)
+ *
+ */
+BOOL CDECL HAIKUDRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags)
+{
+    switch (n) {
+    	case ENUM_REGISTRY_SETTINGS:
+    	case ENUM_CURRENT_SETTINGS:
+    	case 0: {
+    		devmode->u1.s2.dmPosition.x = 0;
+    		devmode->u1.s2.dmPosition.y = 0;
+    		devmode->dmPelsWidth = 1920;
+    		devmode->dmPelsHeight = 1080;
+    		devmode->dmDisplayFrequency = 60;
+    		devmode->dmBitsPerPel = 32;
+    		devmode->u1.s2.dmDisplayOrientation = 0;
+    		return TRUE;
+    	}
+    	default:;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *		ChangeDisplaySettingsEx  (HAIKUDRV.@)
+ *
+ */
+LONG CDECL HAIKUDRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
+                                           HWND hwnd, DWORD flags, LPVOID lpvoid )
+{
+    return 0;
+}
diff --git a/dlls/winehaiku.drv/systray.c b/dlls/winehaiku.drv/systray.c
new file mode 100644
index 00000000000..a6ee21766c0
--- /dev/null
+++ b/dlls/winehaiku.drv/systray.c
@@ -0,0 +1,74 @@
+/*
+ * X11 system tray management
+ *
+ * Copyright (C) 2004 Mike Hearn, for CodeWeavers
+ * Copyright (C) 2005 Robert Shearman
+ * Copyright (C) 2008 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commctrl.h"
+#include "shellapi.h"
+
+#include "haikudrv.h"
+#include "wine/list.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(systray);
+
+
+/***********************************************************************
+ *              wine_notify_icon   (HAIKUDRV.@)
+ *
+ * Driver-side implementation of Shell_NotifyIcon.
+ */
+int CDECL wine_notify_icon( DWORD msg, NOTIFYICONDATAW *data )
+{
+    BOOL ret = FALSE;
+
+    switch (msg)
+    {
+    case NIM_ADD:
+        break;
+    case NIM_DELETE:
+        break;
+    case NIM_MODIFY:
+        break;
+    case NIM_SETVERSION:
+        break;
+    case 0xdead:  /* Wine extension: owner window has died */
+        break;
+    default:
+        FIXME( "unhandled tray message: %u\n", msg );
+        break;
+    }
+    return ret;
+}
diff --git a/dlls/winehaiku.drv/version.rc b/dlls/winehaiku.drv/version.rc
new file mode 100644
index 00000000000..56c62174719
--- /dev/null
+++ b/dlls/winehaiku.drv/version.rc
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2007 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WINE_FILEDESCRIPTION_STR "Wine X11 driver"
+#define WINE_FILENAME_STR "winex11.drv"
+
+#include "wine/wine_common_ver.rc"
diff --git a/dlls/winehaiku.drv/vidmode.c b/dlls/winehaiku.drv/vidmode.c
new file mode 100644
index 00000000000..0930257d57b
--- /dev/null
+++ b/dlls/winehaiku.drv/vidmode.c
@@ -0,0 +1,57 @@
+/*
+ * DirectDraw XVidMode interface
+ *
+ * Copyright 2001 TransGaming Technologies, Inc.
+ * Copyright 2020 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <dlfcn.h>
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+
+#include "haikudrv.h"
+
+#include "windef.h"
+#include "wingdi.h"
+#include "wine/debug.h"
+#include "wine/heap.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(vidmode);
+
+
+/***********************************************************************
+ *		GetDeviceGammaRamp (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_GetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp)
+{
+  return FALSE;
+}
+
+/***********************************************************************
+ *		SetDeviceGammaRamp (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_SetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp)
+{
+  return FALSE;
+}
diff --git a/dlls/winehaiku.drv/vulkan.cpp b/dlls/winehaiku.drv/vulkan.cpp
new file mode 100644
index 00000000000..32929122ff7
--- /dev/null
+++ b/dlls/winehaiku.drv/vulkan.cpp
@@ -0,0 +1,418 @@
+extern "C" {
+#include "config.h"
+#include "haikudrv.h"
+#include "wine/heap.h"
+#include "wine/debug.h"
+
+#define WINE_VK_HOST
+
+#include "wine/vulkan.h"
+#include "wine/vulkan_driver.h"
+}
+#include <AutoDeleter.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
+
+
+#define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface"
+typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT;
+typedef struct VkHeadlessSurfaceCreateInfoEXT {
+    VkStructureType                    sType;
+    const void*                        pNext;
+    VkHeadlessSurfaceCreateFlagsEXT    flags;
+} VkHeadlessSurfaceCreateInfoEXT;
+
+enum {
+	VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000
+};
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance, const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+
+
+static void *haikudrv_get_vk_device_proc_addr(const char *name);
+static void *haikudrv_get_vk_instance_proc_addr(VkInstance instance, const char *name);
+
+
+static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
+        VkInstanceCreateInfo *dst)
+{
+    unsigned int i;
+    const char **enabled_extensions = NULL;
+
+    dst->sType = src->sType;
+    dst->flags = src->flags;
+    dst->pApplicationInfo = src->pApplicationInfo;
+    dst->pNext = src->pNext;
+    dst->enabledLayerCount = 0;
+    dst->ppEnabledLayerNames = NULL;
+    dst->enabledExtensionCount = 0;
+    dst->ppEnabledExtensionNames = NULL;
+    
+    TRACE("sType: %d\n", dst->sType);
+    TRACE("dst->flags: %d\n", dst->flags);
+    TRACE("dst->pApplicationInfo->sType: %d\n", dst->pApplicationInfo->sType);
+    TRACE("dst->pApplicationInfo->pApplicationName: \"%s\"\n", dst->pApplicationInfo->pApplicationName);
+    TRACE("dst->pApplicationInfo->pEngineName: \"%s\"\n", dst->pApplicationInfo->pEngineName);
+    TRACE("dst->pApplicationInfo->apiVersion: %d\n", dst->pApplicationInfo->apiVersion);
+    TRACE("dst->pNext: %p\n", dst->pNext);
+    ((VkApplicationInfo*)dst->pApplicationInfo)->apiVersion = 4194304;
+/*
+    enabled_extensions = heap_calloc(2, sizeof(*src->ppEnabledExtensionNames));
+    enabled_extensions[0] = "VK_KHR_surface";
+    enabled_extensions[1] = "VK_EXT_headless_surface";
+    dst->ppEnabledExtensionNames = enabled_extensions;
+    dst->enabledExtensionCount = 2;
+    return VK_SUCCESS;
+*/
+    if (src->enabledExtensionCount > 0)
+    {
+        enabled_extensions = (const char**)heap_calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
+        if (!enabled_extensions)
+        {
+            ERR("Failed to allocate memory for enabled extensions\n");
+            return VK_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+        for (i = 0; i < src->enabledExtensionCount; i++)
+        {
+            if (
+            	!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_surface")
+            )
+            {
+                enabled_extensions[i] = "VK_EXT_headless_surface";
+            }
+            else
+            {
+                enabled_extensions[i] = src->ppEnabledExtensionNames[i];
+            }
+            TRACE("enabled_extensions[%d]: \"%s\"\n", i, enabled_extensions[i]);
+        }
+        dst->ppEnabledExtensionNames = enabled_extensions;
+        dst->enabledExtensionCount = src->enabledExtensionCount;
+    }
+
+    return VK_SUCCESS;
+}
+
+static const char *wine_vk_native_fn_name(const char *name)
+{
+    if (strcmp(name, "vkCreateWin32SurfaceKHR") == 0) {
+    	return "vkCreateHeadlessSurfaceEXT";
+    }
+    if (strcmp(name, "vkGetPhysicalDeviceWin32PresentationSupportKHR") == 0) {
+    	return "vkCreateHeadlessSurfaceEXT";
+    }
+    return name;
+}
+
+
+//#pragma mark -
+
+class VKWineSurface {
+};
+
+class VKWineImage {
+private:
+	VkImage fImage;
+	VkDeviceMemory fMemory;
+};
+
+class VKWineSwapchain {
+private:
+	ArrayDeleter<VKWineImage> fImages;
+
+public:
+	VKWineSwapchain(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo);
+};
+
+
+//#pragma mark -
+
+static VkResult haikudrv_vkCreateInstance(const VkInstanceCreateInfo *create_info,
+        const VkAllocationCallbacks *allocator, VkInstance *instance)
+{
+    VkInstanceCreateInfo create_info_host;
+    VkResult res;
+    TRACE("(create_info: %p, allocator: %p, instance: %p)\n", create_info, allocator, instance);
+
+    if (allocator)
+        FIXME("Support for allocation callbacks not implemented yet\n");
+
+    /* Perform a second pass on converting VkInstanceCreateInfo. Winevulkan
+     * performed a first pass in which it handles everything except for WSI
+     * functionality such as VK_KHR_win32_surface. Handle this now.
+     */
+    res = wine_vk_instance_convert_create_info(create_info, &create_info_host);
+    if (res != VK_SUCCESS)
+    {
+        ERR("Failed to convert instance create info, res=%d\n", res);
+        return res;
+    }
+
+    res = vkCreateInstance(&create_info_host, NULL /* allocator */, instance);
+
+    heap_free((void *)create_info_host.ppEnabledExtensionNames);
+    return res;
+}
+
+static VkResult haikudrv_vkCreateSwapchainKHR(VkDevice device,
+        const VkSwapchainCreateInfoKHR *create_info,
+        const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
+{
+	TRACE("()\n");
+	return vkCreateSwapchainKHR(device, create_info, allocator, swapchain);
+}
+
+static VkResult haikudrv_vkCreateWin32SurfaceKHR(VkInstance instance,
+        const VkWin32SurfaceCreateInfoKHR *create_info,
+        const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
+{
+	TRACE("()\n");
+	PFN_vkCreateHeadlessSurfaceEXT proc = (PFN_vkCreateHeadlessSurfaceEXT)
+		vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT");
+	VkHeadlessSurfaceCreateInfoEXT surfaceCreateInfo = {};
+	surfaceCreateInfo.sType = (VkStructureType)VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT;
+	return proc(instance, &surfaceCreateInfo, allocator, surface);
+}
+
+static void haikudrv_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
+{
+	TRACE("()\n");
+	vkDestroyInstance(instance, allocator);
+}
+
+static void haikudrv_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
+        const VkAllocationCallbacks *allocator)
+{
+	TRACE("()\n");
+	vkDestroySurfaceKHR(instance, surface, allocator);
+}
+
+static void haikudrv_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
+         const VkAllocationCallbacks *allocator)
+{
+	TRACE("()\n");
+	vkDestroySwapchainKHR(device, swapchain, allocator);
+}
+
+static VkResult haikudrv_vkEnumerateInstanceExtensionProperties(const char *layer_name,
+        uint32_t *count, VkExtensionProperties* properties)
+{
+    unsigned int i;
+    BOOL seen_surface = FALSE;
+    VkResult res;
+
+    TRACE("layer_name %s, count %p, properties %p\n", debugstr_a(layer_name), count, properties);
+
+    /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
+    if (layer_name)
+    {
+        ERR("Layer enumeration not supported from ICD.\n");
+        return VK_ERROR_LAYER_NOT_PRESENT;
+    }
+
+    /* We will return at most the same number of instance extensions reported by the host back to
+     * winevulkan. Along the way we may replace MoltenVK extensions with their win32 equivalents,
+     * or remove redundant extensions outright.
+     * Winevulkan will perform more detailed filtering as it knows whether it has thunks
+     * for a particular extension.
+     */
+    res = vkEnumerateInstanceExtensionProperties(layer_name, count, properties);
+    if (!properties || res < 0)
+        return res;
+
+    for (i = 0; i < *count; i++)
+    {
+        /* For now the only MoltenVK extensions we need to fixup. Long-term we may need an array. */
+        if (!strcmp(properties[i].extensionName, "VK_EXT_headless_surface"))
+        {
+            if (seen_surface)
+            {
+                /* If we've already seen a surface extension, just hide this one. */
+                memmove(properties + i, properties + i + 1, (*count - i - 1) * sizeof(*properties));
+                --*count;
+                --i;
+                continue;
+            }
+            TRACE("Substituting %s for VK_KHR_win32_surface\n", properties[i].extensionName);
+
+            snprintf(properties[i].extensionName, sizeof(properties[i].extensionName),
+                    VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
+            properties[i].specVersion = VK_KHR_WIN32_SURFACE_SPEC_VERSION;
+            seen_surface = TRUE;
+        }
+    }
+
+    TRACE("Returning %u extensions.\n", *count);
+    return res;
+}
+
+static void *haikudrv_vkGetDeviceProcAddr(VkDevice device, const char *name)
+{
+    void *proc_addr;
+
+    TRACE("(%p, %s)\n", device, debugstr_a(name));
+
+    if (!vkGetDeviceProcAddr(device, wine_vk_native_fn_name(name))) {
+        ERR("%s not found\n", debugstr_a(name));
+        return NULL;
+    }
+
+    if ((proc_addr = haikudrv_get_vk_device_proc_addr(name)))
+        return proc_addr;
+
+    return (void*)vkGetDeviceProcAddr(device, name);
+}
+
+static void *haikudrv_vkGetInstanceProcAddr(VkInstance instance, const char *name)
+{
+    void *proc_addr;
+
+    TRACE("(%p, %s)\n", instance, debugstr_a(name));
+
+    if (!vkGetInstanceProcAddr(instance, wine_vk_native_fn_name(name))) {
+        ERR("%s not found\n", debugstr_a(name));
+        return NULL;
+    }
+
+    if ((proc_addr = haikudrv_get_vk_instance_proc_addr(instance, name)))
+        return proc_addr;
+
+    return (void*)vkGetInstanceProcAddr(instance, name);
+}
+
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice phys_dev,
+        const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *capabilities)
+{
+	TRACE("()\n");
+	return vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev, surface_info, capabilities);
+}
+
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev,
+        VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities)
+{
+	TRACE("()\n");
+	return vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, surface, capabilities);
+}
+
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice phys_dev,
+        const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, uint32_t *count, VkSurfaceFormat2KHR *formats)
+{
+	TRACE("()\n");
+	return vkGetPhysicalDeviceSurfaceFormats2KHR(phys_dev, surface_info, count, formats);
+}
+
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice phys_dev,
+        VkSurfaceKHR surface, uint32_t *count, VkSurfaceFormatKHR *formats)
+{
+	TRACE("()\n");
+	return vkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, surface, count, formats);
+}
+
+static VkResult haikudrv_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice phys_dev,
+        VkSurfaceKHR surface, uint32_t *count, VkPresentModeKHR *modes)
+{
+	TRACE("()\n");
+	return vkGetPhysicalDeviceSurfacePresentModesKHR(phys_dev, surface, count, modes);
+}
+
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice phys_dev,
+        uint32_t index, VkSurfaceKHR surface, VkBool32 *supported)
+{
+	TRACE("()\n");
+	return vkGetPhysicalDeviceSurfaceSupportKHR(phys_dev, index, surface, supported);
+}
+
+static VkBool32 haikudrv_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
+        uint32_t index)
+{
+	TRACE("()\n");
+	return VK_TRUE;
+}
+
+static VkResult haikudrv_vkGetSwapchainImagesKHR(VkDevice device,
+        VkSwapchainKHR swapchain, uint32_t *count, VkImage *images)
+{
+	TRACE("()\n");
+	return vkGetSwapchainImagesKHR(device, swapchain, count, images);
+}
+
+static VkResult haikudrv_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info)
+{
+	TRACE("()\n");
+	return vkQueuePresentKHR(queue, present_info);
+}
+
+static VkSurfaceKHR haikudrv_wine_get_native_surface(VkSurfaceKHR surface)
+{
+	TRACE("0x%s\n", wine_dbgstr_longlong(surface));
+	return surface;
+}
+
+
+#define VULKAN_HOOK(name) .p_##name = haikudrv_##name
+static const struct vulkan_funcs vulkan_funcs =
+{
+    VULKAN_HOOK(vkCreateInstance),
+    VULKAN_HOOK(vkCreateSwapchainKHR),
+    VULKAN_HOOK(vkCreateWin32SurfaceKHR),
+    VULKAN_HOOK(vkDestroyInstance),
+    VULKAN_HOOK(vkDestroySurfaceKHR),
+    VULKAN_HOOK(vkDestroySwapchainKHR),
+    VULKAN_HOOK(vkEnumerateInstanceExtensionProperties),
+    // vkGetDeviceGroupSurfacePresentModesKHR
+    VULKAN_HOOK(vkGetDeviceProcAddr),
+    VULKAN_HOOK(vkGetInstanceProcAddr),
+    // vkGetPhysicalDevicePresentRectanglesKHR
+    VULKAN_HOOK(vkGetPhysicalDeviceSurfaceCapabilities2KHR),
+    VULKAN_HOOK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR),
+    VULKAN_HOOK(vkGetPhysicalDeviceSurfaceFormats2KHR),
+    VULKAN_HOOK(vkGetPhysicalDeviceSurfaceFormatsKHR),
+    VULKAN_HOOK(vkGetPhysicalDeviceSurfacePresentModesKHR),
+    VULKAN_HOOK(vkGetPhysicalDeviceSurfaceSupportKHR),
+    VULKAN_HOOK(vkGetPhysicalDeviceWin32PresentationSupportKHR),
+    VULKAN_HOOK(vkGetSwapchainImagesKHR),
+    VULKAN_HOOK(vkQueuePresentKHR),
+
+    VULKAN_HOOK(wine_get_native_surface)
+};
+#undef VULKAN_HOOK
+
+static void *haikudrv_get_vk_device_proc_addr(const char *name)
+{
+    TRACE("(\"%s\")\n", name);
+    return get_vulkan_driver_device_proc_addr(&vulkan_funcs, name);
+}
+
+static void *haikudrv_get_vk_instance_proc_addr(VkInstance instance, const char *name)
+{
+    TRACE("(\"%s\")\n", name);
+    return get_vulkan_driver_instance_proc_addr(&vulkan_funcs, instance, name);
+}
+
+
+static const struct vulkan_funcs *get_vulkan_driver(UINT version)
+{
+    TRACE("()\n");
+    if (version != WINE_VULKAN_DRIVER_VERSION)
+    {
+        ERR("version mismatch, vulkan wants %u but driver has %u\n", version, WINE_VULKAN_DRIVER_VERSION);
+        return NULL;
+    }
+
+    return &vulkan_funcs;
+}
+
+
+const struct vulkan_funcs *CDECL HAIKUDRV_wine_get_vulkan_driver(PHYSDEV dev, UINT version)
+{
+    TRACE("()\n");
+    const struct vulkan_funcs *ret;
+
+    if (!(ret = get_vulkan_driver( version )))
+    {
+        dev = GET_NEXT_PHYSDEV( dev, wine_get_vulkan_driver );
+        ret = dev->funcs->wine_get_vulkan_driver( dev, version );
+    }
+    return ret;
+}
diff --git a/dlls/winehaiku.drv/window.cpp b/dlls/winehaiku.drv/window.cpp
new file mode 100644
index 00000000000..26667b2ad0c
--- /dev/null
+++ b/dlls/winehaiku.drv/window.cpp
@@ -0,0 +1,1393 @@
+/*
+ * Window related functions
+ *
+ * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
+ * Copyright 1993 David Metcalfe
+ * Copyright 1995, 1996 Alex Korobka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define thread_info haiku_thread_info
+
+#include <MessageQueue.h>
+#include <Application.h>
+#include <Window.h>
+#include <View.h>
+#include <Bitmap.h>
+#include <Screen.h>
+#include <OS.h>
+#include <Autolock.h>
+#include <locks.h>
+
+#undef thread_info
+
+#include <map>
+
+
+/* avoid conflict with field names in included win32 headers */
+#undef Status
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+
+extern "C" {
+#include "haikudrv.h"
+#include "wine/debug.h"
+#include "wine/server.h"
+}
+
+#undef SendMessage
+
+WINE_DEFAULT_DEBUG_CHANNEL(haikudrv);
+
+static HWND sCaptureWnd = NULL;
+
+enum {
+	windowResizedMsg = 1,
+};
+
+
+//#pragma mark -
+
+struct haikudrv_thread_data {
+};
+
+
+static WORD sVkFromHaikuKeycodes[256];
+static WORD sScanFromHaikuKeycodes[256];
+static uint8 sHaikuFromVkKeycodes[256];
+static key_map *sHaikuKeymap = NULL; // TODO: call free() on exit
+static char *sHaikuKeymapChars = NULL; // TODO: call free() on exit
+
+
+static void WriteSet(uint32 val)
+{
+	printf("{");
+	bool first = true;
+	for (uint32 i = 0; i < 32; i++) {
+		if ((1 << i) & val) {
+			if (first) first = false; else printf(", ");
+			printf("%" B_PRIu32, i);
+		}
+	}
+	printf("}");
+}
+
+
+static void FromHaikuKeyCode(WORD &vkey, WORD &scan, int32 key)
+{
+	switch (key) {
+		case 0x01: vkey = VK_ESCAPE; scan = 0x01; break;
+		case 0x02: vkey = VK_F1; scan = 0x3b; break;
+		case 0x03: vkey = VK_F2; scan = 0x3c; break;
+		case 0x04: vkey = VK_F3; scan = 0x3d; break;
+		case 0x05: vkey = VK_F4; scan = 0x3e; break;
+		case 0x06: vkey = VK_F5; scan = 0x3f; break;
+		case 0x07: vkey = VK_F6; scan = 0x40; break;
+		case 0x08: vkey = VK_F7; scan = 0x41; break;
+		case 0x09: vkey = VK_F8; scan = 0x42; break;
+		case 0x0a: vkey = VK_F9; scan = 0x43; break;
+		case 0x0b: vkey = VK_F10; scan = 0x44; break;
+		case 0x0c: vkey = VK_F11; scan = 0x57; break;
+		case 0x0d: vkey = VK_F12; scan = 0x58; break;
+		case 0x0e: vkey = VK_SNAPSHOT; scan = 0; break;
+		case 0x0f: vkey = VK_SCROLL; scan = 0; break;
+
+		case 0x12: vkey = '1'; scan = 0x02; break;
+		case 0x13: vkey = '2'; scan = 0x03; break;
+		case 0x14: vkey = '3'; scan = 0x04; break;
+		case 0x15: vkey = '4'; scan = 0x05; break;
+		case 0x16: vkey = '5'; scan = 0x06; break;
+		case 0x17: vkey = '6'; scan = 0x07; break;
+		case 0x18: vkey = '7'; scan = 0x08; break;
+		case 0x19: vkey = '8'; scan = 0x09; break;
+		case 0x1a: vkey = '9'; scan = 0x0a; break;
+		case 0x1b: vkey = '0'; scan = 0x0b; break;
+		case 0x1c: vkey = VK_OEM_MINUS; scan = 0x0c; break;
+		case 0x1d: vkey = VK_OEM_7; scan = 0x0d; break;
+		case 0x1e: vkey = VK_BACK; scan = 0x0e; break;
+		case 0x1f: vkey = VK_INSERT; scan = 0; break;
+
+		case 0x26: vkey = VK_TAB; scan = 0x0f; break;
+		case 0x27: vkey = 'Q'; scan = 0x10; break;
+		case 0x28: vkey = 'W'; scan = 0x11; break;
+		case 0x29: vkey = 'E'; scan = 0x12; break;
+		case 0x2a: vkey = 'R'; scan = 0x13; break;
+		case 0x2b: vkey = 'T'; scan = 0x14; break;
+		case 0x2c: vkey = 'Y'; scan = 0x15; break;
+		case 0x2d: vkey = 'U'; scan = 0x16; break;
+		case 0x2e: vkey = 'I'; scan = 0x17; break;
+		case 0x2f: vkey = 'O'; scan = 0x18; break;
+		case 0x30: vkey = 'P'; scan = 0x19; break;	
+		case 0x31: vkey = VK_OEM_3; scan = 0; break;
+		case 0x32: vkey = VK_OEM_4; scan = 0; break;
+		case 0x33: vkey = VK_OEM_6; scan = 0; break;
+		case 0x34: vkey = VK_DELETE; scan = 0; break;
+	
+		case 0x3b: vkey = VK_CAPITAL; scan = 0x3a; break;	
+		case 0x3c: vkey = 'A'; scan = 0x1e; break;
+		case 0x3d: vkey = 'S'; scan = 0x1f; break;
+		case 0x3e: vkey = 'D'; scan = 0x20; break;
+		case 0x3f: vkey = 'F'; scan = 0x21; break;
+		case 0x40: vkey = 'G'; scan = 0x22; break;
+		case 0x41: vkey = 'H'; scan = 0x23; break;
+		case 0x42: vkey = 'J'; scan = 0x24; break;
+		case 0x43: vkey = 'K'; scan = 0x25; break;
+		case 0x44: vkey = 'L'; scan = 0x26; break;
+		case 0x45: vkey = VK_OEM_PLUS; scan = 0x27; break;
+		case 0x46: vkey = VK_OEM_1; scan = 0x28; break;
+		case 0x47: vkey = VK_RETURN; scan = 0x1c; break;
+
+		case 0x4b: vkey = VK_LSHIFT; scan = 0x2a; break;	
+		case 0x4c: vkey = 'Z'; scan = 0x2c; break;
+		case 0x4d: vkey = 'X'; scan = 0x2d; break;
+		case 0x4e: vkey = 'C'; scan = 0x2e; break;
+		case 0x4f: vkey = 'V'; scan = 0x2f; break;
+		case 0x50: vkey = 'B'; scan = 0x30; break;
+		case 0x51: vkey = 'N'; scan = 0x31; break;
+		case 0x52: vkey = 'M'; scan = 0x32; break;	
+		case 0x53: vkey = VK_OEM_COMMA; scan = 0x33; break;
+		case 0x54: vkey = VK_OEM_PERIOD; scan = 0x34; break;
+		case 0x55: vkey = VK_OEM_2; scan = 0x35; break;
+		case 0x56: vkey = VK_RSHIFT; scan = 0x36; break;	
+		case 0x57: vkey = VK_UP; scan = 0; break;
+
+		case 0x5c: vkey = VK_LCONTROL; scan = 0; break;
+		case 0x5d: vkey = VK_LMENU; scan = 0x38; break;
+		case 0x5e: vkey = VK_SPACE; scan = 0x39; break;
+
+		case 0x61: vkey = VK_LEFT; scan = 0; break;
+		case 0x62: vkey = VK_DOWN; scan = 0; break;
+		case 0x63: vkey = VK_RIGHT; scan = 0; break;
+
+		case 0x66: vkey = VK_LWIN; scan = 0; break;
+		case 0x68: vkey = VK_APPS; scan = 0; break;
+
+		case 0x6a: vkey = VK_OEM_5; scan = 0; break;
+		case 0x6b: vkey = VK_OEM_102; scan = 0; break;
+
+		default: vkey = 0; scan = 0;
+	}
+}
+
+static void InitKeymap()
+{
+	for (int i = 0; i < 256; i++) {
+		FromHaikuKeyCode(sVkFromHaikuKeycodes[i], sScanFromHaikuKeycodes[i], i);
+	}
+	for (int i = 0; i < 256; i++) {
+		sHaikuFromVkKeycodes[sVkFromHaikuKeycodes[i]] = i;
+	}
+
+	get_key_map(&sHaikuKeymap, &sHaikuKeymapChars);
+}
+
+static uint32 HaikuModifiersFromKeyState(const BYTE *lpKeyState)
+{
+	uint32 modifiers = 0;
+	if (lpKeyState[VK_MENU   ] & 0x80) modifiers |= B_COMMAND_KEY;
+	if (lpKeyState[VK_SHIFT  ] & 0x80) modifiers |= B_SHIFT_KEY;
+	if (lpKeyState[VK_CONTROL] & 0x80) modifiers |= B_CONTROL_KEY;
+	if (lpKeyState[VK_LWIN   ] & 0x80) modifiers |= B_OPTION_KEY;
+	if (lpKeyState[VK_NUMLOCK] & 0x01) modifiers |= B_NUM_LOCK;
+	if (lpKeyState[VK_CAPITAL] & 0x01) modifiers |= B_CAPS_LOCK;
+	if (lpKeyState[VK_SCROLL ] & 0x01) modifiers |= B_SCROLL_LOCK;
+	return modifiers;
+}
+
+static void MapKey(char *&chars, size_t &len, int32 key, uint32 modifiers)
+{
+	char *ch;
+	switch (modifiers & (B_SHIFT_KEY | B_CONTROL_KEY | B_OPTION_KEY | B_CAPS_LOCK)) {
+		case B_OPTION_KEY | B_CAPS_LOCK | B_SHIFT_KEY: ch = sHaikuKeymapChars + sHaikuKeymap->option_caps_shift_map[key]; break;
+		case B_OPTION_KEY | B_CAPS_LOCK:               ch = sHaikuKeymapChars + sHaikuKeymap->option_caps_map[key];       break;
+		case B_OPTION_KEY | B_SHIFT_KEY:               ch = sHaikuKeymapChars + sHaikuKeymap->option_shift_map[key];      break;
+		case B_OPTION_KEY:                             ch = sHaikuKeymapChars + sHaikuKeymap->option_map[key];            break;
+		case B_CAPS_LOCK  | B_SHIFT_KEY:               ch = sHaikuKeymapChars + sHaikuKeymap->caps_shift_map[key];        break;
+		case B_CAPS_LOCK:                              ch = sHaikuKeymapChars + sHaikuKeymap->caps_map[key];              break;
+		case B_SHIFT_KEY:                              ch = sHaikuKeymapChars + sHaikuKeymap->shift_map[key];             break;
+		default:
+			if (modifiers & B_CONTROL_KEY)               ch = sHaikuKeymapChars + sHaikuKeymap->control_map[key];
+			else                                         ch = sHaikuKeymapChars + sHaikuKeymap->normal_map[key];
+	}
+	len = *ch;
+	chars = ch + 1;
+}
+
+
+//#pragma mark -
+
+class WineView: public BView {
+private:
+	HWND fHwnd;
+	struct haikudrv_thread_data *fData;
+	BBitmap *fBitmap;
+	uint32 fOldMouseBtns;
+
+public:
+	WineView(HWND hwnd, struct haikudrv_thread_data *data, BRect frame, const char *name);
+	void UpdateBitmap(BBitmap *bitmap, BRect dirty);
+	void MessageReceived(BMessage *msg);
+
+};
+
+class WineWindow: public BWindow {
+private:
+	WineView *fView;
+	HWND fHwnd;
+	struct haikudrv_thread_data *fData;
+	
+public:
+	mutex fCreateMutex;
+	window_surface *fSurface;
+	bool fSendResizeEvents;
+	bool fInDestroy;
+	RECT fNonClient;
+	//HANDLE fEvent;
+
+	WineWindow(HWND hwnd, struct haikudrv_thread_data *data, BRect frame);
+	virtual ~WineWindow();
+	
+	bool QuitRequested() override;
+
+	void FrameMoved(BPoint newPosition) override;
+	void FrameResized(float newWidth, float newHeight) override;
+
+	HWND Handle() {return fHwnd;}
+	WineView *View() {return fView;}
+};
+
+class WineApplication: public BApplication {
+public:
+	WineApplication();
+};
+
+
+WineView::WineView(HWND hwnd, struct haikudrv_thread_data *data, BRect frame, const char *name):
+	BView(frame, name, B_FOLLOW_NONE, B_SUBPIXEL_PRECISE),
+	fHwnd(hwnd),
+	fData(data),
+	fBitmap(NULL),
+	fOldMouseBtns(0)
+{
+}
+
+void WineView::UpdateBitmap(BBitmap *bitmap, BRect dirty)
+{
+	if (bitmap != fBitmap) {
+		fBitmap = bitmap;
+		SetViewBitmap(fBitmap, B_FOLLOW_LEFT_TOP, 0);
+	}
+	Invalidate(dirty);
+}
+
+void WineView::MessageReceived(BMessage *msg)
+{
+	if (sCaptureWnd != NULL && sCaptureWnd != fHwnd) {
+		return BView::MessageReceived(msg);
+	}
+	switch (msg->what) {
+		case B_KEY_DOWN:
+		case B_KEY_UP:
+		case B_UNMAPPED_KEY_DOWN:
+		case B_UNMAPPED_KEY_UP: {
+			HWND hwnd = fHwnd;
+			//msg->FindPointer("hwnd", (void**)&hwnd);
+			int32 key;
+			msg->FindInt32("key", &key);
+
+	    INPUT input;
+	    input.type           = INPUT_KEYBOARD;
+	    input.ki.dwFlags     = (msg->what == B_KEY_UP || msg->what == B_UNMAPPED_KEY_UP) ? KEYEVENTF_KEYUP : 0;
+	    input.ki.time        = GetTickCount();
+	    input.ki.dwExtraInfo = 0;
+			FromHaikuKeyCode(input.ki.wVk, input.ki.wScan, key);
+
+			if (input.ki.wVk != 0) {
+				UnlockLooper();
+				__wine_send_input(hwnd, &input, NULL);
+				LockLooper();
+			}
+			return;
+		}
+		case B_MOUSE_DOWN:
+		case B_MOUSE_UP:
+		case B_MOUSE_MOVED: {
+			HWND hwnd = fHwnd;
+			//msg->FindPointer("hwnd", (void**)&hwnd);
+			BPoint where;
+			uint32 btns;
+			msg->FindPoint("screen_where", &where);
+			msg->FindInt32("buttons", (int32*)&btns);
+			//msg->FindInt32("old_buttons", (int32*)&oldBtns);
+			uint32 oldBtns = (msg->what == B_MOUSE_MOVED) ? btns : fOldMouseBtns;
+			fOldMouseBtns = btns;
+			uint32 btnsDown = btns & (~oldBtns);
+			uint32 btnsUp = oldBtns & (~btns);
+
+			INPUT input;
+			input.type = INPUT_MOUSE;
+			input.mi.dx          = (int)where.x;
+			input.mi.dy          = (int)where.y;
+			input.mi.mouseData   = 0;
+			input.mi.dwFlags     = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
+			input.mi.time        = GetTickCount();
+			input.mi.dwExtraInfo = 0;
+
+			if ((1 << 0) & btnsDown) input.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
+			if ((1 << 1) & btnsDown) input.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
+			if ((1 << 2) & btnsDown) input.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
+			if ((1 << 0) & btnsUp)   input.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
+			if ((1 << 1) & btnsUp)   input.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
+			if ((1 << 2) & btnsUp)   input.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
+
+			UnlockLooper();
+			__wine_send_input(hwnd, &input, NULL);
+			LockLooper();
+			return;
+		}
+		case B_MOUSE_WHEEL_CHANGED: {
+			HWND hwnd;
+			msg->FindPointer("hwnd", (void**)&hwnd);
+			float dx, dy;
+			if (msg->FindFloat("be:wheel_delta_x", &dx) < B_OK) dx = 0;
+			if (msg->FindFloat("be:wheel_delta_y", &dy) < B_OK) dy = 0;
+			int dxInt = int(-dx*WHEEL_DELTA);
+			int dyInt = int(-dy*WHEEL_DELTA);
+			DWORD time = GetTickCount();
+			if (dxInt != 0) {
+				INPUT input;
+				input.type = INPUT_MOUSE;
+				input.mi.dx          = 0;
+				input.mi.dy          = 0;
+				input.mi.mouseData   = dxInt;
+				input.mi.dwFlags     = MOUSEEVENTF_HWHEEL;
+				input.mi.time        = time;
+				input.mi.dwExtraInfo = 0;
+				UnlockLooper();
+				__wine_send_input(hwnd, &input, NULL);
+				LockLooper();
+			}
+			if (dyInt != 0) {
+				INPUT input;
+				input.type = INPUT_MOUSE;
+				input.mi.dx          = 0;
+				input.mi.dy          = 0;
+				input.mi.mouseData   = dyInt;
+				input.mi.dwFlags     = MOUSEEVENTF_WHEEL;
+				input.mi.time        = time;
+				input.mi.dwExtraInfo = 0;
+				UnlockLooper();
+				__wine_send_input(hwnd, &input, NULL);
+				LockLooper();
+			}
+			return;
+		}
+	}
+/*
+	switch (msg->what) {
+		case B_KEY_DOWN:
+		case B_KEY_UP:
+		case B_UNMAPPED_KEY_DOWN:
+		case B_UNMAPPED_KEY_UP: {
+			msg->AddPointer("hwnd", fHwnd);
+			be_app_messenger.SendMessage(msg);
+			return;
+		}
+		case B_MOUSE_DOWN:
+		case B_MOUSE_UP:
+		case B_MOUSE_MOVED: {
+			msg->AddPointer("hwnd", fHwnd);
+			msg->AddInt32("old_buttons", (int32)fOldMouseBtns);
+			msg->FindInt32("buttons", (int32*)&fOldMouseBtns);
+			be_app_messenger.SendMessage(msg);
+			return;
+		}
+		case B_MOUSE_WHEEL_CHANGED: {
+			msg->AddPointer("hwnd", fHwnd);				
+			be_app_messenger.SendMessage(msg);
+			return;
+		}
+	}
+*/
+	BView::MessageReceived(msg);
+}
+
+
+WineWindow::WineWindow(HWND hwnd, struct haikudrv_thread_data *data, BRect frame):
+	BWindow(frame, "TestApp", B_NO_BORDER_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS),
+	fHwnd(hwnd),
+	fData(data),
+	fCreateMutex(MUTEX_INITIALIZER("create window")),
+	fSurface(NULL),
+	fSendResizeEvents(false),
+	fInDestroy(false),
+	fNonClient({0, 0, 0, 0})
+{
+	fView = new WineView(fHwnd, fData, Frame().OffsetToCopy(B_ORIGIN), "view");
+	fView->SetResizingMode(B_FOLLOW_ALL);
+	AddChild(fView, NULL);
+	fView->MakeFocus();
+}
+
+WineWindow::~WineWindow()
+{}
+
+bool WineWindow::QuitRequested()
+{
+	if (fInDestroy) return true;
+	Unlock();
+	HWND hwnd = fHwnd;
+   if (IsWindowEnabled(hwnd))
+   {
+       HMENU hSysMenu;
+
+       if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) {
+         Lock();
+       	return false;
+       }
+       hSysMenu = GetSystemMenu(hwnd, FALSE);
+       if (hSysMenu)
+       {
+           UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
+           if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED))) {
+               Lock();
+               return false;
+           }
+       }
+#if 0
+       if (GetActiveWindow() != hwnd)
+       {
+           LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
+                                      (WPARAM)GetAncestor( hwnd, GA_ROOT ),
+                                      MAKELPARAM( HTCLOSE, WM_NCLBUTTONDOWN ) );
+           switch(ma)
+           {
+               case MA_NOACTIVATEANDEAT:
+               case MA_ACTIVATEANDEAT:
+                   Lock();
+                   return false;
+               case MA_NOACTIVATE:
+                   break;
+               case MA_ACTIVATE:
+               case 0:
+                   SetActiveWindow(hwnd);
+                   break;
+               default:
+                   WARN( "unknown WM_MOUSEACTIVATE code %d\n", (int) ma );
+                   break;
+           }
+       }
+#endif
+       PostMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
+   }
+	Lock();
+	return false;
+}
+
+void WineWindow::FrameMoved(BPoint newPosition)
+{
+	if (!fSendResizeEvents) return;
+	Unlock();
+	SetWindowPos(fHwnd, 0, (int)newPosition.x - fNonClient.left, (int)newPosition.y - fNonClient.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
+	Lock();
+}
+
+void WineWindow::FrameResized(float newWidth, float newHeight)
+{
+	if (!fSendResizeEvents) return;
+	Unlock();
+	SetWindowPos(fHwnd, 0, 0, 0, (int)newWidth + 1 + fNonClient.left + fNonClient.right, (int)newHeight + 1 + fNonClient.top + fNonClient.bottom, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
+	Lock();
+}
+
+
+WineApplication::WineApplication(): BApplication("application/x-vnd.Test-Wine")
+{
+	InitKeymap();
+}
+
+//#pragma mark -
+
+
+DWORD sAppThread = 0;
+std::map<HWND, WineWindow*> *sWindows;
+
+static UINT CALLBACK AppThread(void *arg)
+{
+	rename_thread(find_thread(NULL), "application");
+	be_app->Lock();
+	be_app->Run();
+	return 0;
+}
+
+BOOL HaikuStartApplication()
+{
+	if (be_app != NULL) {
+		ERR("be_app != NULL");
+		_exit(1);
+	}
+	
+	sWindows = new std::map<HWND, WineWindow*>();
+
+	new WineApplication();
+	be_app->Unlock();
+	CloseHandle(CreateThread(NULL, 0, AppThread, NULL, 0, &sAppThread));
+	return TRUE;
+}
+
+static UINT CALLBACK WindowThread(void *arg)
+{
+	rename_thread(find_thread(NULL), "window");
+	auto wnd = (WineWindow*)arg;
+	wnd->Lock();
+	mutex_unlock(&wnd->fCreateMutex);
+	wnd->Loop();
+	return 0;
+}
+
+static WineWindow* HaikuThisWindow(HWND hwnd, bool create = true)
+{
+	BAutolock lock(be_app);
+	auto it = sWindows->find(hwnd);
+	if (it != sWindows->end())
+		return it->second;
+	
+	if (!create)
+		return NULL;
+
+	//struct haikudrv_thread_data *data = haikudrv_init_thread_data();
+	WineWindow *window = new WineWindow(hwnd, NULL, BRect());
+	(*sWindows)[hwnd] = window;
+	mutex_lock(&window->fCreateMutex);
+	window->Unlock();
+	CloseHandle(CreateThread(NULL, 0, WindowThread, window, 0, &sAppThread));
+	mutex_lock(&window->fCreateMutex);
+	return window;
+}
+
+
+//#pragma mark - window_surface
+
+struct haikudrv_window_surface: public window_surface {
+    RECT                  bounds;
+    void                 *bits;
+    BBitmap              *bitmap;
+    WineWindow           *window;
+    CRITICAL_SECTION      crit;
+    BITMAPINFO            info;   /* variable size, must be last */
+};
+
+static struct haikudrv_window_surface *get_x11_surface(struct window_surface *surface)
+{
+    return (struct haikudrv_window_surface *)surface;
+}
+
+static inline int get_dib_info_size(const BITMAPINFO *info, UINT coloruse)
+{
+	return FIELD_OFFSET( BITMAPINFO, bmiColors[0] );
+/*
+	if (info->bmiHeader.biCompression == BI_BITFIELDS)
+		return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
+	if (coloruse == DIB_PAL_COLORS)
+		return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
+	if (!info->bmiHeader.biClrUsed && info->bmiHeader.biBitCount <= 8)
+		return FIELD_OFFSET( BITMAPINFO, bmiColors[1 << info->bmiHeader.biBitCount] );
+	return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
+*/
+}
+
+
+static void CDECL haikudrv_surface_lock(struct window_surface *window_surface)
+{
+	struct haikudrv_window_surface *surface = get_x11_surface(window_surface);
+	EnterCriticalSection(&surface->crit);
+}
+
+static void CDECL haikudrv_surface_unlock(struct window_surface *window_surface)
+{
+	struct haikudrv_window_surface *surface = get_x11_surface(window_surface);
+	LeaveCriticalSection(&surface->crit);
+}
+
+static void *CDECL haikudrv_surface_get_bitmap_info(struct window_surface *window_surface, BITMAPINFO *info)
+{
+	struct haikudrv_window_surface *surface = get_x11_surface( window_surface );
+	
+	memcpy( info, &surface->info, get_dib_info_size(&surface->info, DIB_RGB_COLORS));
+	return surface->bits;
+}
+
+static RECT *CDECL haikudrv_surface_get_bounds(struct window_surface *window_surface)
+{
+	struct haikudrv_window_surface *surface = get_x11_surface(window_surface);
+	return &surface->bounds;
+}
+
+static void CDECL haikudrv_surface_set_region(struct window_surface *window_surface, HRGN region)
+{
+	struct haikudrv_window_surface *surface = get_x11_surface(window_surface);
+	
+	window_surface->funcs->lock(window_surface);
+	// ...
+	window_surface->funcs->unlock(window_surface);
+}
+
+static void CDECL haikudrv_surface_flush(struct window_surface *window_surface)
+{
+	struct haikudrv_window_surface *surface = get_x11_surface(window_surface);
+	
+	window_surface->funcs->lock(window_surface);
+	//FIXME("(): stub\n");
+	RECT dirty;
+	SetRect(&dirty, 0, 0, surface->rect.right - surface->rect.left, surface->rect.bottom - surface->rect.top);
+	if (IntersectRect( &dirty, &dirty, &surface->bounds )) {
+		surface->window->Lock();
+		BRect dirtyRect(dirty.left, dirty.top, dirty.right - 1, dirty.bottom - 1);
+		surface->window->View()->UpdateBitmap(surface->bitmap, dirtyRect);
+		surface->window->Unlock();
+	}
+	reset_bounds(&surface->bounds);
+	window_surface->funcs->unlock(window_surface);
+}
+
+static void CDECL haikudrv_surface_destroy(struct window_surface *window_surface)
+{
+	struct haikudrv_window_surface *surface = get_x11_surface( window_surface );
+	
+	delete surface->bitmap; surface->bitmap = NULL;
+	surface->crit.DebugInfo->Spare[0] = 0;
+	DeleteCriticalSection(&surface->crit);
+	HeapFree(GetProcessHeap(), 0, surface);
+}
+
+static const struct window_surface_funcs haikudrv_surface_funcs = {
+	haikudrv_surface_lock,
+	haikudrv_surface_unlock,
+	haikudrv_surface_get_bitmap_info,
+	haikudrv_surface_get_bounds,
+	haikudrv_surface_set_region,
+	haikudrv_surface_flush,
+	haikudrv_surface_destroy
+};
+
+struct window_surface *create_surface(WineWindow *window, const RECT *rect, COLORREF color_key, BOOL use_alpha)
+{
+	struct haikudrv_window_surface *surface;
+	int width = rect->right - rect->left, height = rect->bottom - rect->top;
+
+	surface = (haikudrv_window_surface*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(struct haikudrv_window_surface, info.bmiColors[0]));
+	if (!surface) return NULL;
+
+	surface->window = window;
+
+	surface->info.bmiHeader.biSize        = sizeof(surface->info.bmiHeader);
+	surface->info.bmiHeader.biWidth       = width;
+	surface->info.bmiHeader.biHeight      = -height; /* top-down */
+	surface->info.bmiHeader.biPlanes      = 1;
+	surface->info.bmiHeader.biBitCount    = 32;
+	surface->info.bmiHeader.biSizeImage   = 4*width*height;
+	surface->info.bmiHeader.biCompression = BI_RGB;
+	surface->info.bmiHeader.biClrUsed = 0;
+
+	InitializeCriticalSection( &surface->crit );
+	surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
+
+	surface->funcs = &haikudrv_surface_funcs;
+	surface->rect  = *rect;
+	surface->ref   = 1;
+	reset_bounds(&surface->bounds);
+
+	surface->bitmap = new BBitmap(BRect(0, 0, width - 1, height - 1), B_RGBA32);
+	if (!surface->bitmap) {
+		goto failed;
+	}
+	surface->bits = surface->bitmap->Bits();
+
+	return surface;
+
+failed:
+	haikudrv_surface_destroy(surface);
+	return NULL;
+}
+
+
+//#pragma mark -
+
+/***********************************************************************
+ *           ThreadDetach (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_ThreadDetach(void)
+{
+#if 0
+    struct haikudrv_thread_data *data = (struct haikudrv_thread_data*)TlsGetValue( thread_data_tls_index );
+
+    if (data)
+    {
+        delete data;
+        /* clear data in case we get re-entered from user32 before the thread is truly dead */
+        TlsSetValue( thread_data_tls_index, NULL );
+    }
+#endif
+}
+
+
+/***********************************************************************
+ *           HAIKUDRV thread initialisation routine
+ */
+struct haikudrv_thread_data *haikudrv_init_thread_data(void)
+{
+    struct haikudrv_thread_data *data = haikudrv_thread_data();
+
+    if (data) return data;
+
+    if (!(data = new(std::nothrow) struct haikudrv_thread_data()))
+    {
+        ERR( "could not create data\n" );
+        ExitProcess(1);
+    }
+
+    TlsSetValue( thread_data_tls_index, data );
+
+    return data;
+}
+
+//#pragma mark -
+
+struct has_popup_result
+{
+    HWND hwnd;
+    BOOL found;
+};
+
+static BOOL is_managed( HWND hwnd )
+{
+    WineWindow *wnd = HaikuThisWindow(hwnd, false);
+    return wnd != NULL;
+}
+
+static BOOL CALLBACK has_managed_popup( HWND hwnd, LPARAM lparam )
+{
+    struct has_popup_result *result = (struct has_popup_result *)lparam;
+
+    if (hwnd == result->hwnd) return FALSE;  /* popups are always above owner */
+    if (GetWindow( hwnd, GW_OWNER ) != result->hwnd) return TRUE;
+    result->found = is_managed( hwnd );
+    return !result->found;
+}
+
+static BOOL has_owned_popups( HWND hwnd )
+{
+    struct has_popup_result result;
+
+    result.hwnd = hwnd;
+    result.found = FALSE;
+    EnumWindows( has_managed_popup, (LPARAM)&result );
+    return result.found;
+}
+
+static BOOL is_window_managed( HWND hwnd, UINT swp_flags, const RECT *window_rect )
+{
+    DWORD style, ex_style;
+
+    /* child windows are not managed */
+    style = GetWindowLongW( hwnd, GWL_STYLE );
+    if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) return FALSE;
+    return TRUE;
+
+    /* activated windows are managed */
+    if (!(swp_flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) return TRUE;
+    if (hwnd == GetActiveWindow()) return TRUE;
+    /* windows with caption are managed */
+    if ((style & WS_CAPTION) == WS_CAPTION) return TRUE;
+    /* windows with thick frame are managed */
+    if (style & WS_THICKFRAME) return TRUE;
+    if (style & WS_POPUP) {
+        HMONITOR hmon;
+        MONITORINFO mi;
+
+        /* popup with sysmenu == caption are managed */
+        if (style & WS_SYSMENU) return TRUE;
+        /* full-screen popup windows are managed */
+        hmon = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY );
+        mi.cbSize = sizeof( mi );
+        GetMonitorInfoW( hmon, &mi );
+        if (window_rect->left <= mi.rcWork.left && window_rect->right >= mi.rcWork.right &&
+            window_rect->top <= mi.rcWork.top && window_rect->bottom >= mi.rcWork.bottom)
+            return TRUE;
+    }
+    /* application windows are managed */
+    ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
+    if (ex_style & WS_EX_APPWINDOW) return TRUE;
+    /* windows that own popups are managed */
+    if (has_owned_popups( hwnd )) return TRUE;
+    /* default: not managed */
+    return FALSE;
+}
+
+
+
+/**********************************************************************
+ *              is_owned_by
+ */
+static BOOL is_owned_by(HWND hwnd, HWND maybe_owner)
+{
+    while (1)
+    {
+        HWND hwnd2 = GetWindow(hwnd, GW_OWNER);
+        if (!hwnd2)
+            hwnd2 = GetAncestor(hwnd, GA_ROOT);
+        if (!hwnd2 || hwnd2 == hwnd)
+            break;
+        if (hwnd2 == maybe_owner)
+            return TRUE;
+        hwnd = hwnd2;
+    }
+
+    return FALSE;
+}
+
+
+/**********************************************************************
+ *              is_all_the_way_front
+ */
+static BOOL is_all_the_way_front(HWND hwnd)
+{
+    BOOL topmost = (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
+    HWND prev = hwnd;
+
+    while ((prev = GetWindow(prev, GW_HWNDPREV)))
+    {
+        if (!topmost && (GetWindowLongW(prev, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0)
+            return TRUE;
+        if (!is_owned_by(prev, hwnd))
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rect )
+{
+    *surface_rect = (RECT){0, 0, 4096, 4096};
+
+    if (!IntersectRect( surface_rect, surface_rect, visible_rect )) return FALSE;
+    OffsetRect( surface_rect, -visible_rect->left, -visible_rect->top );
+    surface_rect->left &= ~31;
+    surface_rect->top  &= ~31;
+    surface_rect->right  = max( surface_rect->left + 32, (surface_rect->right + 31) & ~31 );
+    surface_rect->bottom = max( surface_rect->top + 32, (surface_rect->bottom + 31) & ~31 );
+    return TRUE;
+}
+
+static RECT get_virtual_screen_rect()
+{
+	BRect frame = BScreen().Frame();
+	return RECT{
+		.left   = (int)frame.left,
+		.top    = (int)frame.top,
+		.right  = (int)frame.right + 1,
+		.bottom = (int)frame.bottom + 1,
+	};
+}
+
+static void GetHaikuWindowFlags(
+	uint32 &flags,
+	window_look &look,
+	window_feel &feel,
+	WineWindow *wnd,
+	DWORD style, DWORD ex_style,
+	const RECT *window_rect,
+	const RECT *client_rect
+)
+{
+    flags = B_NOT_CLOSABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE | B_NOT_RESIZABLE |
+    	B_ASYNCHRONOUS_CONTROLS | B_WILL_ACCEPT_FIRST_CLICK;
+    look = B_NO_BORDER_WINDOW_LOOK;
+    feel = B_NORMAL_WINDOW_FEEL;
+
+    //if (disable_window_decorations) return;
+    if (IsRectEmpty(window_rect)) return;
+    if (EqualRect(window_rect, client_rect)) return;
+
+    if ((style & WS_CAPTION) == WS_CAPTION && !(ex_style & WS_EX_LAYERED))
+    {
+        look = B_MODAL_WINDOW_LOOK;
+        if (true/*!data->shaped*/)
+        {
+            look = B_TITLED_WINDOW_LOOK;
+            if (style & WS_SYSMENU) flags &= ~B_NOT_CLOSABLE;
+            if (style & WS_MINIMIZEBOX) flags &= ~B_NOT_MINIMIZABLE;
+            if (style & WS_MAXIMIZEBOX) flags &= ~B_NOT_ZOOMABLE;
+            if (ex_style & WS_EX_TOOLWINDOW) look = B_FLOATING_WINDOW_LOOK;
+        }
+    }
+    if (style & WS_THICKFRAME)
+    {
+        if (look == B_NO_BORDER_WINDOW_LOOK) look = B_MODAL_WINDOW_LOOK;
+        if (true/*!data->shaped*/) flags &= ~B_NOT_RESIZABLE;
+    }
+    else if (ex_style & WS_EX_DLGMODALFRAME) {if (look == B_NO_BORDER_WINDOW_LOOK) look = B_MODAL_WINDOW_LOOK;}
+    else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) {if (look == B_NO_BORDER_WINDOW_LOOK) look = B_MODAL_WINDOW_LOOK;}
+}
+
+
+/*****************************************************************
+ *		SetWindowText   (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_SetWindowText( HWND hwnd, LPCWSTR text )
+{
+	UINT count;
+	char *utf8_buffer;
+	count = WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), NULL, 0, NULL, NULL);
+	if (!(utf8_buffer = (char*)HeapAlloc( GetProcessHeap(), 0, count + 1 ))) {
+		return;
+	}
+	WideCharToMultiByte(CP_UTF8, 0, text, strlenW(text), utf8_buffer, count, NULL, NULL);
+	utf8_buffer[count] = 0;
+
+	//FIXME("(%ld, \"%s\"): stub\n", (long)hwnd, utf8_buffer);
+
+	WineWindow *wnd = HaikuThisWindow(hwnd, false);
+	if (wnd == NULL) return;
+	wnd->Lock();
+	wnd->SetTitle(utf8_buffer);
+	wnd->Unlock();
+
+	HeapFree( GetProcessHeap(), 0, utf8_buffer );
+}
+
+
+/***********************************************************************
+ *		SetWindowStyle   (HAIKUDRV.@)
+ *
+ * Update the X state of a window to reflect a style change
+ */
+void CDECL HAIKUDRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+
+/***********************************************************************
+ *		DestroyWindow   (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_DestroyWindow( HWND hwnd )
+{
+	//FIXME("(%ld): stub\n", (long)hwnd);
+	WineWindow *wnd = HaikuThisWindow(hwnd, false);
+	if (wnd == NULL) return;
+	wnd->Lock();
+	wnd->fInDestroy = true;
+	BMessenger(wnd).SendMessage(B_QUIT_REQUESTED);
+	wnd->Unlock();
+}
+
+
+/**********************************************************************
+ *		CreateDesktopWindow   (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_CreateDesktopWindow( HWND hwnd )
+{
+	//FIXME("(%ld): stub\n", (long)hwnd);
+    RECT oldRect;
+
+    /* retrieve the real size of the desktop */
+    SERVER_START_REQ( get_window_rectangles )
+    {
+        req->handle = wine_server_user_handle( hwnd );
+        req->relative = COORDS_CLIENT;
+        wine_server_call( req );
+        oldRect.left   = reply->window.left;
+        oldRect.top    = reply->window.top;
+        oldRect.right  = reply->window.right;
+        oldRect.bottom = reply->window.bottom;
+    }
+    SERVER_END_REQ;
+
+    RECT rect = get_virtual_screen_rect();
+    ERR("desktop rect: (%d, %d, %d, %d)\n", rect.left, rect.top, rect.right, rect.bottom);
+    if (!EqualRect(&oldRect, &rect))
+    {
+
+        SERVER_START_REQ( set_window_pos )
+        {
+            req->handle        = wine_server_user_handle( hwnd );
+            req->previous      = 0;
+            req->swp_flags     = SWP_NOZORDER;
+            req->window.left   = rect.left;
+            req->window.top    = rect.top;
+            req->window.right  = rect.right;
+            req->window.bottom = rect.bottom;
+            req->client        = req->window;
+            wine_server_call( req );
+        }
+        SERVER_END_REQ;
+    }
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *		CreateWindow   (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_CreateWindow( HWND hwnd )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+	return TRUE;
+}
+
+
+/***********************************************************************
+ *		HAIKUDRV_GetDC   (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_GetDC( HDC hdc, HWND hwnd, HWND top, const RECT *win_rect,
+                         const RECT *top_rect, DWORD flags )
+{
+	//FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+
+/***********************************************************************
+ *		HAIKUDRV_ReleaseDC  (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_ReleaseDC( HWND hwnd, HDC hdc )
+{
+	//FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+
+/*************************************************************************
+ *		ScrollDC   (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update )
+{
+	FIXME("(%ld): stub\n", (long)hdc);
+	return FALSE;
+}
+
+
+/***********************************************************************
+ *		SetCapture  (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_SetCapture( HWND hwnd, UINT flags )
+{
+	FIXME("(%ld, %x): stub\n", (long)hwnd, flags);
+	return;
+	if (hwnd == sCaptureWnd) return;
+	WineWindow* prevWnd = HaikuThisWindow(sCaptureWnd, false);
+	if (prevWnd != NULL) {
+		prevWnd->Lock();
+		prevWnd->View()->SetEventMask(0);
+		prevWnd->Unlock();
+	}
+	WineWindow* nextWnd = HaikuThisWindow(hwnd, false);
+	if (nextWnd != NULL) {
+		nextWnd->Lock();
+		nextWnd->View()->SetEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS);
+		nextWnd->Unlock();
+	}
+}
+
+
+/*****************************************************************
+ *		SetParent   (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_SetParent( HWND hwnd, HWND parent, HWND old_parent )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+
+/***********************************************************************
+ *		WindowPosChanging   (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags,
+                                     const RECT *window_rect, const RECT *client_rect, RECT *visible_rect,
+                                     struct window_surface **surface )
+{
+	//FIXME("(%ld): stub\n", (long)hwnd);
+	ERR("(%ld)\n", (long)hwnd);
+	
+	if (hwnd == GetDesktopWindow()) return TRUE;
+	if (!is_window_managed( hwnd, swp_flags, window_rect )) return TRUE;
+	
+	ERR("window_rect: (%d, %d, %d, %d)\n", window_rect->left, window_rect->top, window_rect->right, window_rect->bottom);
+	ERR("client_rect: (%d, %d, %d, %d)\n", client_rect->left, client_rect->top, client_rect->right, client_rect->bottom);
+	
+	DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
+	DWORD exStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
+	RECT adjRect = *client_rect;
+	AdjustWindowRectEx(&adjRect, style, FALSE, exStyle);
+	adjRect = {
+		client_rect->left - adjRect.left,
+		client_rect->top - adjRect.top,
+		adjRect.right - client_rect->right,
+		adjRect.bottom - client_rect->bottom
+	};
+	*visible_rect = {
+		window_rect->left + adjRect.left,
+		window_rect->top + adjRect.top,
+		window_rect->right - adjRect.right,
+		window_rect->bottom - adjRect.bottom,
+	};
+
+	RECT surface_rect = {
+		0, 0,
+		visible_rect->right - visible_rect->left,
+		visible_rect->bottom - visible_rect->top,
+	};
+	//if (!get_surface_rect( visible_rect, &surface_rect )) return FALSE;
+
+	WineWindow *window = HaikuThisWindow(hwnd);
+
+	if (window->fSurface) {
+		if (EqualRect( &window->fSurface->rect, &surface_rect )) {
+			/* existing surface is good enough */
+			window_surface_add_ref( window->fSurface );
+			*surface = window->fSurface;
+			return TRUE;
+		}
+	}
+
+	*surface = create_surface(window, &surface_rect, 0, FALSE);
+	return TRUE;
+}
+
+
+/***********************************************************************
+ *		WindowPosChanged   (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags,
+                                    const RECT *rectWindow, const RECT *rectClient,
+                                    const RECT *visible_rect, const RECT *valid_rects,
+                                    struct window_surface *surface )
+{
+	ERR("(%ld)\n", (long)hwnd);
+  WineWindow *window = HaikuThisWindow(hwnd, false);
+  if (window == NULL) return;
+
+ 	ERR("(%p, swp_flags: %x)\n", hwnd, swp_flags);
+
+  DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
+  DWORD exStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
+
+  window->Lock();
+  window->fNonClient = {
+		visible_rect->left - rectWindow->left,
+		visible_rect->top  - rectWindow->top,
+		rectWindow->right  - visible_rect->right,
+		rectWindow->bottom - visible_rect->bottom
+  };
+  window->MoveTo(visible_rect->left, visible_rect->top);
+  window->ResizeTo(visible_rect->right - visible_rect->left - 1, visible_rect->bottom - visible_rect->top - 1);
+  
+  uint32 newFlags;
+  window_look newLook;
+  window_feel newFeel;
+  GetHaikuWindowFlags(newFlags, newLook, newFeel, window, style, exStyle, rectWindow, rectClient);
+  if (window->Flags() != newFlags) window->SetFlags(newFlags);
+  if (window->Look() != newLook) window->SetLook(newLook);
+  if (window->Feel() != newFeel) window->SetFeel(newFeel);
+
+  bool newVisible = (style & WS_VISIBLE) != 0;
+  if (newVisible != !window->IsHidden()) {
+  	if (newVisible) {
+  		if (SWP_NOACTIVATE & swp_flags) window->SetFlags(window->Flags() | B_AVOID_FOCUS);
+	  	window->Show();
+  		if (SWP_NOACTIVATE & swp_flags) window->SetFlags(window->Flags() & ~B_AVOID_FOCUS);
+	  	window->fSendResizeEvents = true;
+  	} else {
+	  	window->Hide();
+	  	window->fSendResizeEvents = false;
+  	}
+  } else {
+	  if (!window->IsHidden() && !(SWP_NOACTIVATE & swp_flags)) {
+	  	ERR("(%p): Activate\n", hwnd);
+	  	window->Activate();
+	  }
+  }
+  window->Unlock();
+
+	//FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+/***********************************************************************
+ *           ShowWindow   (HAIKUDRV.@)
+ */
+UINT CDECL HAIKUDRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+	return swp;
+}
+
+
+/**********************************************************************
+ *		SetWindowIcon (HAIKUDRV.@)
+ *
+ * hIcon or hIconSm has changed (or is being initialised for the
+ * first time). Complete the X11 driver-specific initialisation
+ * and set the window hints.
+ */
+void CDECL HAIKUDRV_SetWindowIcon( HWND hwnd, UINT type, HICON icon )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+
+/***********************************************************************
+ *		SetWindowRgn  (HAIKUDRV.@)
+ *
+ * Assign specified region to window (for non-rectangular windows)
+ */
+void CDECL HAIKUDRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+
+/***********************************************************************
+ *		SetLayeredWindowAttributes  (HAIKUDRV.@)
+ *
+ * Set transparency attributes for a layered window.
+ */
+void CDECL HAIKUDRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+}
+
+
+/*****************************************************************************
+ *              UpdateLayeredWindow  (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info,
+                                       const RECT *window_rect )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+	return TRUE;
+}
+
+/**********************************************************************
+ *           HAIKUDRV_WindowMessage   (HAIKUDRV.@)
+ */
+LRESULT CDECL HAIKUDRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+	return 0;
+}
+
+/***********************************************************************
+ *           HAIKUDRV_SysCommand   (HAIKUDRV.@)
+ *
+ * Perform WM_SYSCOMMAND handling.
+ */
+LRESULT CDECL HAIKUDRV_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam )
+{
+	FIXME("(%ld): stub\n", (long)hwnd);
+	return -1;
+}
+
+/***********************************************************************
+ *           HAIKUDRV_FlashWindowEx   (HAIKUDRV.@)
+ */
+void CDECL HAIKUDRV_FlashWindowEx( PFLASHWINFO pfinfo )
+{
+}
+
+/***********************************************************************
+ *           MsgWaitForMultipleObjectsEx   (HAIKUDRV.@)
+ */
+DWORD CDECL HAIKUDRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
+                                                DWORD timeout, DWORD mask, DWORD flags )
+{
+	timeout = timeout < 1000 ? timeout : 1000;
+	//struct haikudrv_thread_data *data = haikudrv_init_thread_data();
+	//if (data == NULL) {
+		if (!count && !timeout) return WAIT_TIMEOUT;
+		return WaitForMultipleObjectsEx(count, handles, flags & MWMO_WAITALL, timeout, flags & MWMO_ALERTABLE);
+	//}
+/*
+	data->ProcessMessages();
+
+	if (!count && !timeout) return WAIT_TIMEOUT;
+	return WaitForMultipleObjectsEx(count, handles, flags & MWMO_WAITALL, timeout, flags & MWMO_ALERTABLE);
+*/
+}
+
+/*****************************************************************
+ *		SetFocus   (HAIKUDRV.@)
+ *
+ * Set the X focus.
+ */
+void CDECL HAIKUDRV_SetFocus( HWND hwnd )
+{
+	FIXME("(%ld)\n", (long)hwnd);
+	if (!(hwnd = GetAncestor(hwnd, GA_ROOT))) return;
+
+	if (hwnd == GetForegroundWindow() && hwnd != GetDesktopWindow() && !is_all_the_way_front(hwnd))
+		SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
+
+  WineWindow *window = HaikuThisWindow(hwnd, false);
+  if (window == NULL) return;
+  window->Activate();
+}
+
+
+/***********************************************************************
+ *		ToUnicodeEx (HAIKUDRV.@)
+ *
+ * The ToUnicode function translates the specified virtual-key code and keyboard
+ * state to the corresponding Windows character or characters.
+ *
+ * If the specified key is a dead key, the return value is negative. Otherwise,
+ * it is one of the following values:
+ * Value	Meaning
+ * 0	The specified virtual key has no translation for the current state of the keyboard.
+ * 1	One Windows character was copied to the buffer.
+ * 2	Two characters were copied to the buffer. This usually happens when a
+ *      dead-key character (accent or diacritic) stored in the keyboard layout cannot
+ *      be composed with the specified virtual key to form a single character.
+ *
+ * FIXME : should do the above (return 2 for non matching deadchar+char combinations)
+ *
+ */
+INT CDECL HAIKUDRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
+                             LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
+{
+    //FIXME("(%u): stub\n", virtKey);
+    if (virtKey >= 256) return -2;
+    uint32 key = sHaikuFromVkKeycodes[virtKey];
+    uint32 modifiers = HaikuModifiersFromKeyState(lpKeyState);
+
+    char *srcChars;
+    size_t srcLen;
+    MapKey(srcChars, srcLen, key, modifiers);
+
+		INT dstLen = MultiByteToWideChar(CP_UTF8, 0, srcChars, srcLen, NULL, 0);
+		MultiByteToWideChar(CP_UTF8, 0, srcChars, srcLen, bufW, bufW_size);
+    return dstLen;
+}
diff --git a/dlls/winehaiku.drv/winehaiku.drv.spec b/dlls/winehaiku.drv/winehaiku.drv.spec
new file mode 100644
index 00000000000..9be88c47358
--- /dev/null
+++ b/dlls/winehaiku.drv/winehaiku.drv.spec
@@ -0,0 +1,29 @@
+# WinTab32
+@ cdecl AttachEventQueueToTablet(long) HAIKUDRV_AttachEventQueueToTablet
+@ cdecl GetCurrentPacket(ptr) HAIKUDRV_GetCurrentPacket
+@ cdecl LoadTabletInfo(long) HAIKUDRV_LoadTabletInfo
+@ cdecl WTInfoW(long long ptr) HAIKUDRV_WTInfoW
+
+# Desktop
+@ cdecl wine_create_desktop(long long) HAIKUDRV_create_desktop
+
+# System tray
+@ cdecl wine_notify_icon(long ptr)
+
+#IME Interface
+@ stdcall ImeInquire(ptr ptr wstr)
+@ stdcall ImeConfigure(long long long ptr)
+@ stdcall ImeDestroy(long)
+@ stdcall ImeEscape(long long ptr)
+@ stdcall ImeSelect(long long)
+@ stdcall ImeSetActiveContext(long long)
+@ stdcall ImeToAsciiEx(long long ptr ptr long long)
+@ stdcall NotifyIME(long long long long)
+@ stdcall ImeRegisterWord(wstr long wstr)
+@ stdcall ImeUnregisterWord(wstr long wstr)
+@ stdcall ImeEnumRegisterWord(ptr wstr long wstr ptr)
+@ stdcall ImeSetCompositionString(long long ptr long ptr long)
+@ stdcall ImeConversionList(long wstr ptr long long)
+@ stdcall ImeProcessKey(long long long ptr)
+@ stdcall ImeGetRegisterWordStyle(long ptr)
+@ stdcall ImeGetImeMenuItems(long long long ptr ptr long)
diff --git a/dlls/winehaiku.drv/wintab.c b/dlls/winehaiku.drv/wintab.c
new file mode 100644
index 00000000000..47e0e9a4681
--- /dev/null
+++ b/dlls/winehaiku.drv/wintab.c
@@ -0,0 +1,69 @@
+/*
+ * X11 tablet driver
+ *
+ * Copyright 2003 CodeWeavers (Aric Stewart)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <dlfcn.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "haikudrv.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+#include "wintab.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
+
+
+/***********************************************************************
+ *             HAIKUDRV_LoadTabletInfo (HAIKUDRV.@)
+ */
+BOOL CDECL HAIKUDRV_LoadTabletInfo(HWND hwnddefault)
+{
+    return FALSE;
+}
+
+/***********************************************************************
+ *		HAIKUDRV_AttachEventQueueToTablet (HAIKUDRV.@)
+ */
+int CDECL HAIKUDRV_AttachEventQueueToTablet(HWND hOwner)
+{
+    return 0;
+}
+
+/***********************************************************************
+ *		HAIKUDRV_GetCurrentPacket (HAIKUDRV.@)
+ */
+int CDECL HAIKUDRV_GetCurrentPacket(/*LPWTPACKET*/void* packet)
+{
+    return 0;
+}
+
+/***********************************************************************
+ *		HAIKUDRV_WTInfoW (HAIKUDRV.@)
+ */
+UINT CDECL HAIKUDRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
+{
+    return 0;
+}
diff --git a/include/wine/server.h b/include/wine/server.h
index 57bcdbbb00d..5f3327b20a8 100644
--- a/include/wine/server.h
+++ b/include/wine/server.h
@@ -70,7 +70,7 @@ static inline data_size_t wine_server_reply_size( const void *reply )
 /* add some data to be sent along with the request */
 static inline void wine_server_add_data( void *req_ptr, const void *ptr, data_size_t size )
 {
-    struct __server_request_info * const req = req_ptr;
+    struct __server_request_info * const req = (struct __server_request_info * const)req_ptr;
     if (size)
     {
         req->data[req->data_count].ptr = ptr;
@@ -82,7 +82,7 @@ static inline void wine_server_add_data( void *req_ptr, const void *ptr, data_si
 /* set the pointer and max size for the reply var data */
 static inline void wine_server_set_reply( void *req_ptr, void *ptr, data_size_t max_size )
 {
-    struct __server_request_info * const req = req_ptr;
+    struct __server_request_info * const req = (struct __server_request_info * const)req_ptr;
     req->reply_data = ptr;
     req->u.req.request_header.reply_size = max_size;
 }
diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h
index c2a2acfc282..853244058d9 100644
--- a/include/wine/vulkan_driver.h
+++ b/include/wine/vulkan_driver.h
@@ -56,17 +56,17 @@ static inline void *get_vulkan_driver_device_proc_addr(
     name += 2;
 
     if (!strcmp(name, "CreateSwapchainKHR"))
-        return vulkan_funcs->p_vkCreateSwapchainKHR;
+        return (void*)vulkan_funcs->p_vkCreateSwapchainKHR;
     if (!strcmp(name, "DestroySwapchainKHR"))
-        return vulkan_funcs->p_vkDestroySwapchainKHR;
+        return (void*)vulkan_funcs->p_vkDestroySwapchainKHR;
     if (!strcmp(name, "GetDeviceGroupSurfacePresentModesKHR"))
-        return vulkan_funcs->p_vkGetDeviceGroupSurfacePresentModesKHR;
+        return (void*)vulkan_funcs->p_vkGetDeviceGroupSurfacePresentModesKHR;
     if (!strcmp(name, "GetDeviceProcAddr"))
-        return vulkan_funcs->p_vkGetDeviceProcAddr;
+        return (void*)vulkan_funcs->p_vkGetDeviceProcAddr;
     if (!strcmp(name, "GetSwapchainImagesKHR"))
-        return vulkan_funcs->p_vkGetSwapchainImagesKHR;
+        return (void*)vulkan_funcs->p_vkGetSwapchainImagesKHR;
     if (!strcmp(name, "QueuePresentKHR"))
-        return vulkan_funcs->p_vkQueuePresentKHR;
+        return (void*)vulkan_funcs->p_vkQueuePresentKHR;
 
     return NULL;
 }
@@ -79,36 +79,36 @@ static inline void *get_vulkan_driver_instance_proc_addr(
     name += 2;
 
     if (!strcmp(name, "CreateInstance"))
-        return vulkan_funcs->p_vkCreateInstance;
+        return (void*)vulkan_funcs->p_vkCreateInstance;
     if (!strcmp(name, "EnumerateInstanceExtensionProperties"))
-        return vulkan_funcs->p_vkEnumerateInstanceExtensionProperties;
+        return (void*)vulkan_funcs->p_vkEnumerateInstanceExtensionProperties;
 
     if (!instance) return NULL;
 
     if (!strcmp(name, "CreateWin32SurfaceKHR"))
-        return vulkan_funcs->p_vkCreateWin32SurfaceKHR;
+        return (void*)vulkan_funcs->p_vkCreateWin32SurfaceKHR;
     if (!strcmp(name, "DestroyInstance"))
-        return vulkan_funcs->p_vkDestroyInstance;
+        return (void*)vulkan_funcs->p_vkDestroyInstance;
     if (!strcmp(name, "DestroySurfaceKHR"))
-        return vulkan_funcs->p_vkDestroySurfaceKHR;
+        return (void*)vulkan_funcs->p_vkDestroySurfaceKHR;
     if (!strcmp(name, "GetInstanceProcAddr"))
-        return vulkan_funcs->p_vkGetInstanceProcAddr;
+        return (void*)vulkan_funcs->p_vkGetInstanceProcAddr;
     if (!strcmp(name, "GetPhysicalDevicePresentRectanglesKHR"))
-        return vulkan_funcs->p_vkGetPhysicalDevicePresentRectanglesKHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDevicePresentRectanglesKHR;
     if (!strcmp(name, "GetPhysicalDeviceSurfaceCapabilities2KHR"))
-        return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceCapabilities2KHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDeviceSurfaceCapabilities2KHR;
     if (!strcmp(name, "GetPhysicalDeviceSurfaceCapabilitiesKHR"))
-        return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
     if (!strcmp(name, "GetPhysicalDeviceSurfaceFormats2KHR"))
-        return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceFormats2KHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDeviceSurfaceFormats2KHR;
     if (!strcmp(name, "GetPhysicalDeviceSurfaceFormatsKHR"))
-        return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR;
     if (!strcmp(name, "GetPhysicalDeviceSurfacePresentModesKHR"))
-        return vulkan_funcs->p_vkGetPhysicalDeviceSurfacePresentModesKHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDeviceSurfacePresentModesKHR;
     if (!strcmp(name, "GetPhysicalDeviceSurfaceSupportKHR"))
-        return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR;
     if (!strcmp(name, "GetPhysicalDeviceWin32PresentationSupportKHR"))
-        return vulkan_funcs->p_vkGetPhysicalDeviceWin32PresentationSupportKHR;
+        return (void*)vulkan_funcs->p_vkGetPhysicalDeviceWin32PresentationSupportKHR;
 
     name -= 2;
 
diff --git a/include/winuser.h b/include/winuser.h
index 898c9034e33..048f86e9956 100644
--- a/include/winuser.h
+++ b/include/winuser.h
@@ -4442,7 +4442,7 @@ struct user_api_hook
     LRESULT (WINAPI *pScrollBarWndProc)(HWND, UINT, WPARAM, LPARAM, BOOL);
 };
 
-WINUSERAPI BOOL WINAPI RegisterUserApiHook(const struct user_api_hook *new, struct user_api_hook *old);
+WINUSERAPI BOOL WINAPI RegisterUserApiHook(const struct user_api_hook *newHook, struct user_api_hook *oldHook);
 WINUSERAPI void WINAPI UnregisterUserApiHook(void);
 #endif
 
diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c
index 6d577dd0fd1..c96a85f2d60 100644
--- a/programs/explorer/desktop.c
+++ b/programs/explorer/desktop.c
@@ -39,7 +39,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(explorer);
 #define DESKTOP_CLASS_ATOM ((LPCWSTR)MAKEINTATOM(32769))
 #define DESKTOP_ALL_ACCESS 0x01ff
 
-static const WCHAR default_driver[] = {'m','a','c',',','x','1','1',0};
+static const WCHAR default_driver[] = L"haiku,mac,x11";
 
 static BOOL using_root;
 
-- 
2.30.2


From 1e8491ce2859de2d937b78bbeca413bd7f4efb30 Mon Sep 17 00:00:00 2001
From: X512 <danger_mail@list.ru>
Date: Thu, 20 Jan 2022 22:28:08 +0900
Subject: winehaiku.drv: stand alone Vulkan WSI implementation

---
 dlls/winehaiku.drv/Makefile.in |   2 +-
 dlls/winehaiku.drv/vulkan.cpp  | 849 ++++++++++++++++++++++++++++++---
 2 files changed, 787 insertions(+), 64 deletions(-)

diff --git a/dlls/winehaiku.drv/Makefile.in b/dlls/winehaiku.drv/Makefile.in
index 0db76dd3a93..6a8d910ed66 100644
--- a/dlls/winehaiku.drv/Makefile.in
+++ b/dlls/winehaiku.drv/Makefile.in
@@ -2,7 +2,7 @@ MODULE    = winehaiku.drv
 IMPORTS   = uuid setupapi rpcrt4 user32 gdi32 advapi32 win32u
 DELAYIMPORTS = comctl32 ole32 shell32 imm32
 EXTRAINCL = -I/boot/system/develop/headers/private/shared
-EXTRALIBS = -lbe -lstdc++ -lvulkan
+EXTRALIBS = -lbe -lgame -lstdc++ -lvulkan
 
 EXTRADLLFLAGS = -mcygwin
 
diff --git a/dlls/winehaiku.drv/vulkan.cpp b/dlls/winehaiku.drv/vulkan.cpp
index 32929122ff7..59bf952ebb7 100644
--- a/dlls/winehaiku.drv/vulkan.cpp
+++ b/dlls/winehaiku.drv/vulkan.cpp
@@ -1,3 +1,5 @@
+#include <locks.h>
+
 extern "C" {
 #include "config.h"
 #include "haikudrv.h"
@@ -9,9 +11,14 @@ extern "C" {
 #include "wine/vulkan.h"
 #include "wine/vulkan_driver.h"
 }
+#include <new>
+#include <cassert>
+#include <algorithm>
+#include <map>
+#include <locks.h>
 #include <AutoDeleter.h>
 
-WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
+WINE_DEFAULT_DEBUG_CHANNEL(haiku_vk);
 
 
 #define VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME "VK_EXT_headless_surface"
@@ -32,6 +39,86 @@ typedef VkResult (VKAPI_PTR *PFN_vkCreateHeadlessSurfaceEXT)(VkInstance instance
 static void *haikudrv_get_vk_device_proc_addr(const char *name);
 static void *haikudrv_get_vk_instance_proc_addr(VkInstance instance, const char *name);
 
+#define VkCheckRet(err) {VkResult _err = (err); if (_err != VK_SUCCESS) return _err;}
+
+
+recursive_lock sDevicesLock = RECURSIVE_LOCK_INITIALIZER("vkDevices");
+std::map<VkDevice, VkPhysicalDevice> *sDevices;
+
+
+static VkPhysicalDevice GetPhysicalDevice(VkDevice dev)
+{
+	RecursiveLocker lock(&sDevicesLock);
+	if (sDevices == NULL)
+		return NULL;
+	auto it = sDevices->find(dev);
+	if (it == sDevices->end())
+		return NULL;
+	return it->second;
+}
+
+static uint32_t getMemoryTypeIndex(VkPhysicalDevice physicalDevice, uint32_t typeBits, VkMemoryPropertyFlags properties) {
+	VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
+	vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
+	for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) {
+		if ((typeBits & 1) == 1) {
+			if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
+				return i;
+			}
+		}
+		typeBits >>= 1;
+	}
+	return 0;
+}
+
+static void insertImageMemoryBarrier(
+	VkCommandBuffer cmdbuffer,
+	VkImage image,
+	VkAccessFlags srcAccessMask,
+	VkAccessFlags dstAccessMask,
+	VkImageLayout oldImageLayout,
+	VkImageLayout newImageLayout,
+	VkPipelineStageFlags srcStageMask,
+	VkPipelineStageFlags dstStageMask,
+	VkImageSubresourceRange subresourceRange)
+{
+	VkImageMemoryBarrier imageMemoryBarrier{
+		.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+		.srcAccessMask = srcAccessMask,
+		.dstAccessMask = dstAccessMask,
+		.oldLayout = oldImageLayout,
+		.newLayout = newImageLayout,
+		.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+		.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+		.image = image,
+		.subresourceRange = subresourceRange
+	};
+
+	vkCmdPipelineBarrier(
+		cmdbuffer,
+		srcStageMask,
+		dstStageMask,
+		0,
+		0, nullptr,
+		0, nullptr,
+		1, &imageMemoryBarrier
+	);
+}
+
+static VkResult submitWork(VkDevice device, VkCommandBuffer cmdBuffer, VkQueue queue)
+{
+	VkSubmitInfo submitInfo{.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO};
+	submitInfo.commandBufferCount = 1;
+	submitInfo.pCommandBuffers = &cmdBuffer;
+	VkFenceCreateInfo fenceInfo{.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
+	VkFence fence;
+	VkCheckRet(vkCreateFence(device, &fenceInfo, nullptr, &fence));
+	VkCheckRet(vkQueueSubmit(queue, 1, &submitInfo, fence));
+	VkCheckRet(vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX));
+	vkDestroyFence(device, fence, nullptr);
+	return VK_SUCCESS;
+}
+
 
 static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
         VkInstanceCreateInfo *dst)
@@ -108,25 +195,570 @@ static const char *wine_vk_native_fn_name(const char *name)
 
 //#pragma mark -
 
-class VKWineSurface {
+class BufferQueue {
+private:
+	ArrayDeleter<int32> fItems;
+	int32 fBeg, fLen, fMaxLen;
+
+public:
+	BufferQueue(int32 maxLen = 0);
+	bool SetMaxLen(int32 maxLen);
+
+	inline int32 Length() {return fLen;}
+	bool Add(int32 val);
+	int32 Remove();
+	int32 Begin();
 };
 
+BufferQueue::BufferQueue(int32 maxLen):
+	fItems((maxLen > 0) ? new int32[maxLen] : NULL),
+	fBeg(0), fLen(0), fMaxLen(maxLen)
+{}
+
+bool BufferQueue::SetMaxLen(int32 maxLen)
+{
+	if (!(maxLen > 0)) {
+		fItems.Unset();
+	} else {
+		auto newItems = new(std::nothrow) int32[maxLen];
+		if (newItems == NULL)
+			return false;
+		fItems.SetTo(newItems);
+	}
+	fMaxLen = maxLen;
+	fBeg = 0; fLen = 0; fMaxLen = maxLen;
+	return true;
+}
+
+
+bool BufferQueue::Add(int32 val)
+{
+	if (!(fLen < fMaxLen))
+		return false;
+	fItems[(fBeg + fLen)%fMaxLen] = val;
+	fLen++;
+	return true;
+}
+
+int32 BufferQueue::Remove()
+{
+	if (!(fLen > 0))
+		return -1;
+	int32 res = fItems[fBeg%fMaxLen];
+	fBeg = (fBeg + 1)%fMaxLen;
+	fLen--;
+	return res;
+}
+
+int32 BufferQueue::Begin()
+{
+	if (!(fLen > 0))
+		return -1;
+	return fItems[fBeg%fMaxLen];
+}
+
+
+//#pragma mark -
+
 class VKWineImage {
 private:
+	VkDevice fDevice;
 	VkImage fImage;
 	VkDeviceMemory fMemory;
+
+public:
+	VKWineImage();
+	~VKWineImage();
+	VkResult Init(VkDevice device, const VkImageCreateInfo &createInfo, bool cpuMem = false);
+
+	VkImage ToHandle() {return fImage;}
+	VkDeviceMemory GetMemoryHandle() {return fMemory;}
+};
+
+class VKWineSurface {
+private:
+	HWND fHwnd;
+public:
+	VKWineSurface();
+	~VKWineSurface();
+	VkResult Init(VkInstance instance, const VkWin32SurfaceCreateInfoKHR &createInfo);
+
+	VkResult GetCapabilities(VkPhysicalDevice physDev, VkSurfaceCapabilitiesKHR *capabilities);
+	VkResult GetFormats(VkPhysicalDevice physDev, uint32_t *count, VkSurfaceFormatKHR *formats);
+	VkResult GetPresentModes(VkPhysicalDevice physDev, uint32_t *count, VkPresentModeKHR *modes);
+	VkResult GetPresentRectangles(VkPhysicalDevice physDev, uint32_t* pRectCount, VkRect2D* pRects);
+
+	static VKWineSurface *FromHandle(VkSurfaceKHR surface) {return (VKWineSurface*)surface;}
+	VkSurfaceKHR ToHandle() {return (VkSurfaceKHR)this;}
+	HWND GetHwnd() {return fHwnd;}
 };
 
 class VKWineSwapchain {
 private:
+	recursive_lock fLock;
+	VkDevice fDevice;
+	VKWineSurface *fSurface;
+	VkExtent2D fImageExtent;
+	uint32 fImageCnt;
 	ArrayDeleter<VKWineImage> fImages;
+	BufferQueue fImagePool;
+	ObjectDeleter<VKWineImage> fBuffer;
+	VkCommandPool fCommandPool;
+	VkQueue fQueue;
+	VkFence fFence;
+
+	VkImageCreateInfo ImageFromCreateInfo(const VkSwapchainCreateInfoKHR &createInfo);
+	VkResult CreateBuffer();
+	VkResult CopyToBuffer(VkImage srcImage, int32_t width, int32_t height);
 
 public:
-	VKWineSwapchain(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo);
+	VKWineSwapchain();
+	~VKWineSwapchain();
+	VkResult Init(VkDevice device, const VkSwapchainCreateInfoKHR &createInfo);
+
+	VkResult GetSwapchainImages(uint32_t *count, VkImage *images);
+	VkResult AcquireNextImage(const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex);
+	VkResult QueuePresent(VkQueue queue, const VkPresentInfoKHR *present_info, uint32_t idx);
+
+	static VKWineSwapchain *FromHandle(VkSwapchainKHR surface) {return (VKWineSwapchain*)surface;}
+	VkSwapchainKHR ToHandle() {return (VkSwapchainKHR)this;}
 };
 
 
-//#pragma mark -
+//#pragma mark - VKWineImage
+
+VKWineImage::VKWineImage():
+	fDevice(NULL), fImage(0), fMemory(0)
+{}
+
+VKWineImage::~VKWineImage()
+{
+	vkFreeMemory(fDevice, fMemory, NULL);
+	vkDestroyImage(fDevice, fImage, NULL);
+}
+
+VkResult VKWineImage::Init(VkDevice device, const VkImageCreateInfo &createInfo, bool cpuMem)
+{
+	fDevice = device;
+
+	VkCheckRet(vkCreateImage(fDevice, &createInfo, NULL, &fImage));
+
+	VkMemoryRequirements memRequirements;
+	vkGetImageMemoryRequirements(device, fImage, &memRequirements);
+	size_t memTypeIdx = 0;
+	if (cpuMem) {
+		memTypeIdx = getMemoryTypeIndex(GetPhysicalDevice(fDevice), memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
+	} else {
+		for (; memTypeIdx < 8 * sizeof(memRequirements.memoryTypeBits); ++memTypeIdx) {
+			if (memRequirements.memoryTypeBits & (1u << memTypeIdx))
+				break;
+		}
+		assert(memTypeIdx <= 8 * sizeof(memRequirements.memoryTypeBits) - 1);
+	}
+
+	VkMemoryAllocateInfo memAllocInfo{
+		.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+		.allocationSize = memRequirements.size,
+		.memoryTypeIndex = (uint32_t)memTypeIdx
+	};
+	VkCheckRet(vkAllocateMemory(device, &memAllocInfo, nullptr, &fMemory));
+	VkCheckRet(vkBindImageMemory(device, fImage, fMemory, 0));
+
+	return VK_SUCCESS;
+}
+
+
+//#pragma mark - VKWineSurface
+
+VKWineSurface::VKWineSurface():
+	fHwnd(NULL)
+{}
+
+VKWineSurface::~VKWineSurface()
+{}
+
+VkResult VKWineSurface::Init(VkInstance instance, const VkWin32SurfaceCreateInfoKHR &createInfo)
+{
+	fHwnd = createInfo.hwnd;
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSurface::GetCapabilities(VkPhysicalDevice physDev, VkSurfaceCapabilitiesKHR *surfaceCapabilities)
+{
+	/* Image count limits */
+	surfaceCapabilities->minImageCount = 1;
+	surfaceCapabilities->maxImageCount = 3;
+
+	/* Surface extents */
+	surfaceCapabilities->currentExtent = {0xffffffff, 0xffffffff};
+	surfaceCapabilities->minImageExtent = {1, 1};
+	/* Ask the device for max */
+	VkPhysicalDeviceProperties devProps;
+	vkGetPhysicalDeviceProperties(physDev, &devProps);
+
+	surfaceCapabilities->maxImageExtent = {
+		devProps.limits.maxImageDimension2D, devProps.limits.maxImageDimension2D
+	};
+	surfaceCapabilities->maxImageArrayLayers = 1;
+
+	/* Surface transforms */
+	surfaceCapabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+	surfaceCapabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+
+	/* Composite alpha */
+	surfaceCapabilities->supportedCompositeAlpha = (VkCompositeAlphaFlagBitsKHR)(
+		VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR | VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
+		VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR | VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR
+	);
+
+	/* Image usage flags */
+	surfaceCapabilities->supportedUsageFlags =
+		VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
+		VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
+	
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSurface::GetFormats(VkPhysicalDevice physDev, uint32_t *count, VkSurfaceFormatKHR *surfaceFormats)
+{
+/*
+	VkFormat formats[] = {VK_FORMAT_B8G8R8A8_UNORM};
+	uint32_t formatCnt = 1;
+*/
+	constexpr int max_core_1_0_formats = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1;
+	VkFormat formats[max_core_1_0_formats];
+	uint32_t formatCnt = 0;
+	
+	for (int format = 0; format < max_core_1_0_formats; format++) {
+		VkImageFormatProperties formatProps;
+		VkResult res = vkGetPhysicalDeviceImageFormatProperties(
+			physDev, (VkFormat)format, VK_IMAGE_TYPE_2D,
+			VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT,
+			&formatProps
+		);
+		if (res != VK_ERROR_FORMAT_NOT_SUPPORTED) {
+			formats[formatCnt++] = (VkFormat)format;
+		}
+	}
+
+	if (surfaceFormats == NULL) {
+		*count = formatCnt;
+		return VK_SUCCESS;
+	}
+	memcpy(surfaceFormats, formats, sizeof(VkFormat)*std::min<uint32_t>(*count, formatCnt));
+	if (*count < formatCnt)
+		return VK_INCOMPLETE;
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSurface::GetPresentModes(VkPhysicalDevice physDev, uint32_t *count, VkPresentModeKHR *presentModes)
+{
+	static const VkPresentModeKHR modes[] = {VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR};
+	if (presentModes == NULL) {
+		*count = B_COUNT_OF(modes);
+		return VK_SUCCESS;
+	}
+	memcpy(presentModes, modes, sizeof(VkPresentModeKHR)*std::min<uint32_t>(*count, B_COUNT_OF(modes)));
+	if (*count < B_COUNT_OF(modes))
+		return VK_INCOMPLETE;
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSurface::GetPresentRectangles(VkPhysicalDevice physDev, uint32_t* pRectCount, VkRect2D* pRects)
+{
+	if (pRects == NULL) {
+		*pRectCount = 1;
+		return VK_SUCCESS;
+	}
+	if (*pRectCount < 1) {
+		return VK_INCOMPLETE;
+	}
+	VkSurfaceCapabilitiesKHR caps;
+	VkCheckRet(GetCapabilities(physDev, &caps));
+	pRects[0].offset.x = 0;
+	pRects[0].offset.y = 0;
+	pRects[0].extent = caps.currentExtent;
+	return VK_SUCCESS;
+}
+
+
+//#pragma mark - VKWineSwapchain
+
+VKWineSwapchain::VKWineSwapchain():
+	fLock(RECURSIVE_LOCK_INITIALIZER("VKWineSwapchain")),
+	fCommandPool(VK_NULL_HANDLE),
+	fFence(VK_NULL_HANDLE)
+{}
+
+VKWineSwapchain::~VKWineSwapchain()
+{
+	if (fCommandPool != VK_NULL_HANDLE) {
+		vkDestroyCommandPool(fDevice, fCommandPool, nullptr);
+		vkQueueWaitIdle(fQueue);
+	}
+
+	vkDestroyFence(fDevice, fFence, NULL);
+	recursive_lock_destroy(&fLock);
+}
+
+VkImageCreateInfo VKWineSwapchain::ImageFromCreateInfo(const VkSwapchainCreateInfoKHR &createInfo)
+{
+	return VkImageCreateInfo{
+		.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+		.pNext = nullptr,
+		.imageType = VK_IMAGE_TYPE_2D,
+		.format = createInfo.imageFormat,
+		.extent = {
+			createInfo.imageExtent.width,
+			createInfo.imageExtent.height,
+			1
+		},
+		.mipLevels = 1,
+		.arrayLayers = createInfo.imageArrayLayers,
+		.samples = VK_SAMPLE_COUNT_1_BIT,
+		.tiling = VK_IMAGE_TILING_OPTIMAL,
+		.usage = createInfo.imageUsage,
+		.sharingMode = createInfo.imageSharingMode,
+		.queueFamilyIndexCount = createInfo.queueFamilyIndexCount,
+		.pQueueFamilyIndices = createInfo.pQueueFamilyIndices,
+		.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
+	};
+}
+
+VkResult VKWineSwapchain::CreateBuffer()
+{
+	VkCommandPoolCreateInfo cmdPoolInfo{
+		.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+		.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
+		.queueFamilyIndex = 0
+	};
+	VkCheckRet(vkCreateCommandPool(fDevice, &cmdPoolInfo, nullptr, &fCommandPool));
+
+	VkImageCreateInfo createInfo{
+		.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+		.imageType = VK_IMAGE_TYPE_2D,
+		.format = VK_FORMAT_R8G8B8A8_UNORM,
+		.extent = {
+			.width = fImageExtent.width,
+			.height = fImageExtent.height,
+			.depth = 1
+		},
+		.mipLevels = 1,
+		.arrayLayers = 1,
+		.samples = VK_SAMPLE_COUNT_1_BIT,
+		.tiling = VK_IMAGE_TILING_LINEAR,
+		.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+		.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
+	};
+	fBuffer.SetTo(new(std::nothrow) VKWineImage());
+	if (!fBuffer.IsSet())
+		return VK_ERROR_OUT_OF_HOST_MEMORY;
+	VkCheckRet(fBuffer->Init(fDevice, createInfo, true));
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSwapchain::CopyToBuffer(VkImage srcImage, int32_t width, int32_t height)
+{
+	// Do the actual blit from the offscreen image to our host visible destination image
+	VkCommandBufferAllocateInfo cmdBufAllocateInfo{
+		.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+		.commandPool = fCommandPool,
+		.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+		.commandBufferCount = 1
+	};
+	VkCommandBuffer copyCmd;
+	VkCheckRet(vkAllocateCommandBuffers(fDevice, &cmdBufAllocateInfo, &copyCmd));
+	VkCommandBufferBeginInfo cmdBufInfo{.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
+	VkCheckRet(vkBeginCommandBuffer(copyCmd, &cmdBufInfo));
+
+	// Transition destination image to transfer destination layout
+	insertImageMemoryBarrier(
+		copyCmd,
+		fBuffer->ToHandle(),
+		0,
+		VK_ACCESS_TRANSFER_WRITE_BIT,
+		VK_IMAGE_LAYOUT_UNDEFINED,
+		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+		VK_PIPELINE_STAGE_TRANSFER_BIT,
+		VK_PIPELINE_STAGE_TRANSFER_BIT,
+		VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
+	);
+
+	// srcImage is already in VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, and does not need to be transitioned
+
+	VkImageCopy imageCopyRegion{};
+	imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	imageCopyRegion.srcSubresource.layerCount = 1;
+	imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+	imageCopyRegion.dstSubresource.layerCount = 1;
+	imageCopyRegion.extent.width = width;
+	imageCopyRegion.extent.height = height;
+	imageCopyRegion.extent.depth = 1;
+
+	vkCmdCopyImage(
+		copyCmd,
+		srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+		fBuffer->ToHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+		1,
+		&imageCopyRegion
+	);
+
+	// Transition destination image to general layout, which is the required layout for mapping the image memory later on
+	insertImageMemoryBarrier(
+		copyCmd,
+		fBuffer->ToHandle(),
+		VK_ACCESS_TRANSFER_WRITE_BIT,
+		VK_ACCESS_MEMORY_READ_BIT,
+		VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+		VK_IMAGE_LAYOUT_GENERAL,
+		VK_PIPELINE_STAGE_TRANSFER_BIT,
+		VK_PIPELINE_STAGE_TRANSFER_BIT,
+		VkImageSubresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}
+	);
+
+	VkCheckRet(vkEndCommandBuffer(copyCmd));
+
+	VkCheckRet(submitWork(fDevice, copyCmd, fQueue));
+	vkFreeCommandBuffers(fDevice, fCommandPool, 1, &copyCmd);
+
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSwapchain::Init(VkDevice device, const VkSwapchainCreateInfoKHR &createInfo)
+{
+	fDevice = device;
+	fSurface = VKWineSurface::FromHandle(createInfo.surface);
+
+	VkFenceCreateInfo fence_info{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, 0};
+	VkCheckRet(vkCreateFence(fDevice, &fence_info, NULL, &fFence));
+
+	fImageExtent.width = createInfo.imageExtent.width;
+	fImageExtent.height = createInfo.imageExtent.height;
+
+	VkImageCreateInfo imageCreateInfo = ImageFromCreateInfo(createInfo);
+
+	fImageCnt = createInfo.minImageCount;
+	fImages.SetTo(new(std::nothrow) VKWineImage[fImageCnt]);
+	if (!fImages.IsSet())
+		return VK_ERROR_OUT_OF_HOST_MEMORY;
+	if(!fImagePool.SetMaxLen(fImageCnt))
+		return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+	for (uint32_t i = 0; i < fImageCnt; i++) {
+		VkCheckRet(fImages[i].Init(device, imageCreateInfo));
+		fImagePool.Add(i);
+	}
+
+	vkGetDeviceQueue(device, 0, 0, &fQueue);
+	//VkCheckRet(vkSetDeviceLoaderData(device, fQueue));
+
+	VkCheckRet(CreateBuffer());
+
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSwapchain::GetSwapchainImages(uint32_t *count, VkImage *images)
+{
+	if (images == NULL) {
+		*count = fImageCnt;
+		return VK_SUCCESS;
+	}
+	uint32_t copyCnt = std::min<uint32_t>(*count, fImageCnt);
+	for (uint32_t i = 0; i < copyCnt; i++) {
+		images[i] = fImages[i].ToHandle();
+	}
+	if (*count < fImageCnt)
+		return VK_INCOMPLETE;
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSwapchain::AcquireNextImage(const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex)
+{
+	int32 imageIdx;
+	for(;;) {
+		recursive_lock_lock(&fLock);
+		imageIdx = fImagePool.Remove();
+		recursive_lock_unlock(&fLock);
+		if (imageIdx < 0) {
+			snooze(100);
+			continue;
+		}
+		break;
+	};
+	*pImageIndex = imageIdx;
+
+	if (VK_NULL_HANDLE != pAcquireInfo->semaphore || VK_NULL_HANDLE != pAcquireInfo->fence) {
+		VkSubmitInfo submit = {VK_STRUCTURE_TYPE_SUBMIT_INFO};
+	
+		if (VK_NULL_HANDLE != pAcquireInfo->semaphore) {
+			submit.signalSemaphoreCount = 1;
+			submit.pSignalSemaphores = &pAcquireInfo->semaphore;
+		}
+	
+		submit.commandBufferCount = 0;
+		submit.pCommandBuffers = nullptr;
+		VkResult retval = vkQueueSubmit(fQueue, 1, &submit, pAcquireInfo->fence);
+		assert(retval == VK_SUCCESS);
+	}
+
+	return VK_SUCCESS;
+}
+
+VkResult VKWineSwapchain::QueuePresent(VkQueue queue, const VkPresentInfoKHR *presentInfo, uint32_t idx)
+{
+	vkResetFences(fDevice, 1, &fFence);
+	VkPipelineStageFlags pipeline_stage_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+
+	VkSubmitInfo submit_info = {
+		VK_STRUCTURE_TYPE_SUBMIT_INFO, NULL, presentInfo->waitSemaphoreCount, presentInfo->pWaitSemaphores, &pipeline_stage_flags, 0, NULL, 0, NULL
+	};
+
+	VkResult result = vkQueueSubmit(queue, 1, &submit_info, fFence);
+	if (result == VK_SUCCESS) {
+		vkWaitForFences(fDevice, 1, &fFence, VK_TRUE, 100000000000);
+	}
+
+	recursive_lock_lock(&fLock);
+	uint32_t imageIdx = presentInfo->pImageIndices[idx];
+
+	CopyToBuffer(fImages[imageIdx].ToHandle(), fImageExtent.width, fImageExtent.height);
+	VKWineImage &srcImage = *fBuffer.Get();
+
+	VkImageSubresource subResource{
+		.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT
+	};
+	VkSubresourceLayout subResourceLayout;
+	vkGetImageSubresourceLayout(fDevice, srcImage.ToHandle(), &subResource, &subResourceLayout);
+	size_t stride = subResourceLayout.rowPitch;
+
+	char *imagedata = NULL;
+	vkMapMemory(fDevice, srcImage.GetMemoryHandle(), 0, VK_WHOLE_SIZE, 0, (void**)&imagedata);
+	imagedata += subResourceLayout.offset;
+
+	HDC hdc = GetDC(fSurface->GetHwnd());
+	BITMAPINFO bitmapInfo{
+		.bmiHeader = {
+			.biSize = sizeof(BITMAPINFOHEADER),
+			.biWidth = (LONG)(stride/4),
+			.biHeight = -(LONG)fImageExtent.height,
+			.biPlanes = 1,
+			.biBitCount = 32,
+			.biCompression = BI_RGB,
+			.biSizeImage = (DWORD)(stride*fImageExtent.height)
+		}
+	};
+	SetDIBitsToDevice(hdc, 0, 0, fImageExtent.width, fImageExtent.height, 0, 0, 0, fImageExtent.height, imagedata, &bitmapInfo, DIB_RGB_COLORS);
+	ReleaseDC(fSurface->GetHwnd(), hdc);
+
+	vkUnmapMemory(fDevice, srcImage.GetMemoryHandle());
+
+	fImagePool.Add(imageIdx);
+	recursive_lock_unlock(&fLock);
+	return VK_SUCCESS;
+}
+
+
+//#pragma mark - Instance
 
 static VkResult haikudrv_vkCreateInstance(const VkInstanceCreateInfo *create_info,
         const VkAllocationCallbacks *allocator, VkInstance *instance)
@@ -155,46 +787,12 @@ static VkResult haikudrv_vkCreateInstance(const VkInstanceCreateInfo *create_inf
     return res;
 }
 
-static VkResult haikudrv_vkCreateSwapchainKHR(VkDevice device,
-        const VkSwapchainCreateInfoKHR *create_info,
-        const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
-{
-	TRACE("()\n");
-	return vkCreateSwapchainKHR(device, create_info, allocator, swapchain);
-}
-
-static VkResult haikudrv_vkCreateWin32SurfaceKHR(VkInstance instance,
-        const VkWin32SurfaceCreateInfoKHR *create_info,
-        const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
-{
-	TRACE("()\n");
-	PFN_vkCreateHeadlessSurfaceEXT proc = (PFN_vkCreateHeadlessSurfaceEXT)
-		vkGetInstanceProcAddr(instance, "vkCreateHeadlessSurfaceEXT");
-	VkHeadlessSurfaceCreateInfoEXT surfaceCreateInfo = {};
-	surfaceCreateInfo.sType = (VkStructureType)VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT;
-	return proc(instance, &surfaceCreateInfo, allocator, surface);
-}
-
 static void haikudrv_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
 {
 	TRACE("()\n");
 	vkDestroyInstance(instance, allocator);
 }
 
-static void haikudrv_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
-        const VkAllocationCallbacks *allocator)
-{
-	TRACE("()\n");
-	vkDestroySurfaceKHR(instance, surface, allocator);
-}
-
-static void haikudrv_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
-         const VkAllocationCallbacks *allocator)
-{
-	TRACE("()\n");
-	vkDestroySwapchainKHR(device, swapchain, allocator);
-}
-
 static VkResult haikudrv_vkEnumerateInstanceExtensionProperties(const char *layer_name,
         uint32_t *count, VkExtensionProperties* properties)
 {
@@ -281,66 +879,123 @@ static void *haikudrv_vkGetInstanceProcAddr(VkInstance instance, const char *nam
     return (void*)vkGetInstanceProcAddr(instance, name);
 }
 
-static VkResult haikudrv_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice phys_dev,
-        const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *capabilities)
+static VkResult VKAPI_CALL haikudrv_vkCreateDevice(
+    VkPhysicalDevice                            physicalDevice,
+    const VkDeviceCreateInfo*                   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkDevice*                                   pDevice)
+{
+	TRACE("()\n");
+	VkCheckRet(vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice));
+
+	RecursiveLocker lock(&sDevicesLock);
+	if (sDevices == NULL) {
+		sDevices = new std::map<VkDevice, VkPhysicalDevice>();
+	}
+	sDevices->emplace(*pDevice, physicalDevice);
+
+	return VK_SUCCESS;
+}
+
+static void VKAPI_CALL haikudrv_vkDestroyDevice(
+    VkDevice                                    device,
+    const VkAllocationCallbacks*                pAllocator)
+{
+	TRACE("()\n");
+
+	{
+		RecursiveLocker lock(&sDevicesLock);
+		auto it = sDevices->find(device);
+		sDevices->erase(it);
+	}
+
+	vkDestroyDevice(device, pAllocator);
+}
+
+//#pragma mark - Surface
+
+static VkResult haikudrv_vkCreateWin32SurfaceKHR(VkInstance instance,
+        const VkWin32SurfaceCreateInfoKHR *createInfo,
+        const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
+{
+	TRACE("()\n");
+
+	auto wineSurface = new(std::nothrow) VKWineSurface();
+	if (wineSurface == NULL)
+		return VK_ERROR_OUT_OF_HOST_MEMORY;
+	VkCheckRet(wineSurface->Init(instance, *createInfo));
+	*surface = wineSurface->ToHandle();
+	return VK_SUCCESS;
+}
+
+static void haikudrv_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *allocator)
 {
 	TRACE("()\n");
-	return vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev, surface_info, capabilities);
+	delete VKWineSurface::FromHandle(surface);
 }
 
-static VkResult haikudrv_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev,
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physDev,
+        const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *capabilities)
+{
+	ERR("(): not implemented\n");
+	return VK_NOT_READY;
+}
+
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physDev,
         VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities)
 {
 	TRACE("()\n");
-	return vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, surface, capabilities);
+	return VKWineSurface::FromHandle(surface)->GetCapabilities(physDev, capabilities);
 }
 
-static VkResult haikudrv_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice phys_dev,
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physDev,
         const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, uint32_t *count, VkSurfaceFormat2KHR *formats)
 {
-	TRACE("()\n");
-	return vkGetPhysicalDeviceSurfaceFormats2KHR(phys_dev, surface_info, count, formats);
+	ERR("(): not implemented\n");
+	return VK_NOT_READY;
 }
 
-static VkResult haikudrv_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice phys_dev,
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physDev,
         VkSurfaceKHR surface, uint32_t *count, VkSurfaceFormatKHR *formats)
 {
 	TRACE("()\n");
-	return vkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, surface, count, formats);
+	return VKWineSurface::FromHandle(surface)->GetFormats(physDev, count, formats);
 }
 
-static VkResult haikudrv_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice phys_dev,
+static VkResult haikudrv_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physDev,
         VkSurfaceKHR surface, uint32_t *count, VkPresentModeKHR *modes)
 {
 	TRACE("()\n");
-	return vkGetPhysicalDeviceSurfacePresentModesKHR(phys_dev, surface, count, modes);
+	return VKWineSurface::FromHandle(surface)->GetPresentModes(physDev, count, modes);
 }
 
-static VkResult haikudrv_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice phys_dev,
+static VkResult haikudrv_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physDev,
         uint32_t index, VkSurfaceKHR surface, VkBool32 *supported)
 {
 	TRACE("()\n");
-	return vkGetPhysicalDeviceSurfaceSupportKHR(phys_dev, index, surface, supported);
+	*supported = VK_TRUE;
+	return VK_SUCCESS;
 }
 
-static VkBool32 haikudrv_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
-        uint32_t index)
+static VkBool32 haikudrv_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physDev, uint32_t index)
 {
 	TRACE("()\n");
 	return VK_TRUE;
 }
 
-static VkResult haikudrv_vkGetSwapchainImagesKHR(VkDevice device,
-        VkSwapchainKHR swapchain, uint32_t *count, VkImage *images)
-{
+static VkResult VKAPI_CALL haikudrv_vkGetDeviceGroupSurfacePresentModesKHR(
+	VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes
+) {
 	TRACE("()\n");
-	return vkGetSwapchainImagesKHR(device, swapchain, count, images);
+	*pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
+	return VK_SUCCESS;
 }
 
-static VkResult haikudrv_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info)
-{
+static VkResult VKAPI_CALL haikudrv_vkGetPhysicalDevicePresentRectanglesKHR(
+	VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects
+) {
 	TRACE("()\n");
-	return vkQueuePresentKHR(queue, present_info);
+	return VKWineSurface::FromHandle(surface)->GetPresentRectangles(physicalDevice, pRectCount, pRects);
 }
 
 static VkSurfaceKHR haikudrv_wine_get_native_surface(VkSurfaceKHR surface)
@@ -350,6 +1005,68 @@ static VkSurfaceKHR haikudrv_wine_get_native_surface(VkSurfaceKHR surface)
 }
 
 
+//#pragma mark - Swapchain
+
+static VkResult haikudrv_vkCreateSwapchainKHR(VkDevice device,
+        const VkSwapchainCreateInfoKHR *createInfo,
+        const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
+{
+	TRACE("()\n");
+	auto wineSwapchain = new(std::nothrow) VKWineSwapchain();
+	if (wineSwapchain == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY;
+	VkCheckRet(wineSwapchain->Init(device, *createInfo));
+	*swapchain = wineSwapchain->ToHandle();
+	return VK_SUCCESS;
+}
+
+static void haikudrv_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *allocator)
+{
+	TRACE("()\n");
+	delete VKWineSwapchain::FromHandle(swapchain);
+}
+
+static VkResult haikudrv_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *count, VkImage *images)
+{
+	TRACE("()\n");
+	return VKWineSwapchain::FromHandle(swapchain)->GetSwapchainImages(count, images);
+}
+
+static VkResult haikudrv_vkAcquireNextImageKHR(
+	VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex
+) {
+	TRACE("()\n");
+	VkAcquireNextImageInfoKHR info{
+		.sType = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
+		.swapchain = swapchain,
+		.timeout = timeout,
+		.semaphore = semaphore,
+		.fence = fence
+	};
+	return VKWineSwapchain::FromHandle(swapchain)->AcquireNextImage(&info, pImageIndex);
+}
+
+static VkResult haikudrv_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
+{
+	TRACE("()\n");
+
+	VkResult ret = VK_SUCCESS;
+	for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) {
+		auto *sc = VKWineSwapchain::FromHandle(pPresentInfo->pSwapchains[i]);
+		VkResult res = sc->QueuePresent(queue, pPresentInfo, i);
+
+		if (pPresentInfo->pResults != nullptr)
+			pPresentInfo->pResults[i] = res;
+
+		if (res != VK_SUCCESS && ret == VK_SUCCESS)
+			ret = res;
+	}
+
+	return ret;
+}
+
+
+//#pragma mark -
+
 #define VULKAN_HOOK(name) .p_##name = haikudrv_##name
 static const struct vulkan_funcs vulkan_funcs =
 {
@@ -360,10 +1077,10 @@ static const struct vulkan_funcs vulkan_funcs =
     VULKAN_HOOK(vkDestroySurfaceKHR),
     VULKAN_HOOK(vkDestroySwapchainKHR),
     VULKAN_HOOK(vkEnumerateInstanceExtensionProperties),
-    // vkGetDeviceGroupSurfacePresentModesKHR
+    VULKAN_HOOK(vkGetDeviceGroupSurfacePresentModesKHR),
     VULKAN_HOOK(vkGetDeviceProcAddr),
     VULKAN_HOOK(vkGetInstanceProcAddr),
-    // vkGetPhysicalDevicePresentRectanglesKHR
+    VULKAN_HOOK(vkGetPhysicalDevicePresentRectanglesKHR),
     VULKAN_HOOK(vkGetPhysicalDeviceSurfaceCapabilities2KHR),
     VULKAN_HOOK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR),
     VULKAN_HOOK(vkGetPhysicalDeviceSurfaceFormats2KHR),
@@ -381,12 +1098,18 @@ static const struct vulkan_funcs vulkan_funcs =
 static void *haikudrv_get_vk_device_proc_addr(const char *name)
 {
     TRACE("(\"%s\")\n", name);
+    if (strcmp(name, "vkAcquireNextImageKHR") == 0)
+    	return (void*)haikudrv_vkAcquireNextImageKHR;
+    if (strcmp(name, "vkDestroyDevice") == 0)
+    	return (void*)haikudrv_vkDestroyDevice;
     return get_vulkan_driver_device_proc_addr(&vulkan_funcs, name);
 }
 
 static void *haikudrv_get_vk_instance_proc_addr(VkInstance instance, const char *name)
 {
     TRACE("(\"%s\")\n", name);
+    if (strcmp(name, "vkCreateDevice") == 0)
+    	return (void*)haikudrv_vkCreateDevice;
     return get_vulkan_driver_instance_proc_addr(&vulkan_funcs, instance, name);
 }
 
-- 
2.30.2


From 619fb2083a29685c115014d3e45b5b00cf285992 Mon Sep 17 00:00:00 2001
From: X512 <danger_mail@list.ru>
Date: Thu, 20 Jan 2022 22:28:58 +0900
Subject: winehaiku.drv: update

---
 dlls/winehaiku.drv/Makefile.in            |  2 +-
 dlls/winehaiku.drv/{mouse.c => mouse.cpp} | 22 +++++++-
 dlls/winehaiku.drv/window.cpp             | 60 ++--------------------
 dlls/winehaiku.drv/window.h               | 62 +++++++++++++++++++++++
 4 files changed, 86 insertions(+), 60 deletions(-)
 rename dlls/winehaiku.drv/{mouse.c => mouse.cpp} (85%)
 create mode 100644 dlls/winehaiku.drv/window.h

diff --git a/dlls/winehaiku.drv/Makefile.in b/dlls/winehaiku.drv/Makefile.in
index 6a8d910ed66..2e0d0232fa5 100644
--- a/dlls/winehaiku.drv/Makefile.in
+++ b/dlls/winehaiku.drv/Makefile.in
@@ -13,7 +13,7 @@ C_SRCS = \
 	ime.c \
 	init.c \
 	keyboard.c \
-	mouse.c \
+	mouse.cpp \
 	settings.cpp \
 	systray.c \
 	window.cpp \
diff --git a/dlls/winehaiku.drv/mouse.c b/dlls/winehaiku.drv/mouse.cpp
similarity index 85%
rename from dlls/winehaiku.drv/mouse.c
rename to dlls/winehaiku.drv/mouse.cpp
index b44039e9d76..cbf4eaafff6 100644
--- a/dlls/winehaiku.drv/mouse.c
+++ b/dlls/winehaiku.drv/mouse.cpp
@@ -25,7 +25,11 @@
 #include <dlfcn.h>
 #include <stdarg.h>
 
+#define thread_info haiku_thread_info
+#include <WindowScreen.h>
+#undef thread_info
 
+extern "C" {
 #define NONAMELESSUNION
 #define OEMRESOURCE
 #include "windef.h"
@@ -36,6 +40,8 @@
 #include "wine/server.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
+}
+
 
 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
 
@@ -59,7 +65,11 @@ void CDECL HAIKUDRV_SetCursor( HCURSOR handle )
  */
 BOOL CDECL HAIKUDRV_SetCursorPos( INT x, INT y )
 {
-    return TRUE;
+/*
+	ERR("(%d, %d)\n", x, y);
+	set_mouse_position(x, y);
+	return TRUE;
+*/
 }
 
 /***********************************************************************
@@ -67,7 +77,15 @@ BOOL CDECL HAIKUDRV_SetCursorPos( INT x, INT y )
  */
 BOOL CDECL HAIKUDRV_GetCursorPos(LPPOINT pos)
 {
-    return TRUE;
+/*
+  ERR("()\n");
+	BPoint haikuPos;
+	if (get_mouse(&haikuPos, NULL) < B_OK)
+		return FALSE;
+	pos->x = haikuPos.x;
+	pos->y = haikuPos.y;
+*/
+	return TRUE;
 }
 
 /***********************************************************************
diff --git a/dlls/winehaiku.drv/window.cpp b/dlls/winehaiku.drv/window.cpp
index 26667b2ad0c..18dcba70c69 100644
--- a/dlls/winehaiku.drv/window.cpp
+++ b/dlls/winehaiku.drv/window.cpp
@@ -29,19 +29,11 @@
 # include <unistd.h>
 #endif
 
-#define thread_info haiku_thread_info
 
-#include <MessageQueue.h>
-#include <Application.h>
-#include <Window.h>
-#include <View.h>
-#include <Bitmap.h>
+#include "window.h"
+
 #include <Screen.h>
-#include <OS.h>
 #include <Autolock.h>
-#include <locks.h>
-
-#undef thread_info
 
 #include <map>
 
@@ -241,52 +233,6 @@ static void MapKey(char *&chars, size_t &len, int32 key, uint32 modifiers)
 
 //#pragma mark -
 
-class WineView: public BView {
-private:
-	HWND fHwnd;
-	struct haikudrv_thread_data *fData;
-	BBitmap *fBitmap;
-	uint32 fOldMouseBtns;
-
-public:
-	WineView(HWND hwnd, struct haikudrv_thread_data *data, BRect frame, const char *name);
-	void UpdateBitmap(BBitmap *bitmap, BRect dirty);
-	void MessageReceived(BMessage *msg);
-
-};
-
-class WineWindow: public BWindow {
-private:
-	WineView *fView;
-	HWND fHwnd;
-	struct haikudrv_thread_data *fData;
-	
-public:
-	mutex fCreateMutex;
-	window_surface *fSurface;
-	bool fSendResizeEvents;
-	bool fInDestroy;
-	RECT fNonClient;
-	//HANDLE fEvent;
-
-	WineWindow(HWND hwnd, struct haikudrv_thread_data *data, BRect frame);
-	virtual ~WineWindow();
-	
-	bool QuitRequested() override;
-
-	void FrameMoved(BPoint newPosition) override;
-	void FrameResized(float newWidth, float newHeight) override;
-
-	HWND Handle() {return fHwnd;}
-	WineView *View() {return fView;}
-};
-
-class WineApplication: public BApplication {
-public:
-	WineApplication();
-};
-
-
 WineView::WineView(HWND hwnd, struct haikudrv_thread_data *data, BRect frame, const char *name):
 	BView(frame, name, B_FOLLOW_NONE, B_SUBPIXEL_PRECISE),
 	fHwnd(hwnd),
@@ -570,7 +516,7 @@ static UINT CALLBACK WindowThread(void *arg)
 	return 0;
 }
 
-static WineWindow* HaikuThisWindow(HWND hwnd, bool create = true)
+WineWindow* HaikuThisWindow(HWND hwnd, bool create)
 {
 	BAutolock lock(be_app);
 	auto it = sWindows->find(hwnd);
diff --git a/dlls/winehaiku.drv/window.h b/dlls/winehaiku.drv/window.h
new file mode 100644
index 00000000000..dc737c38fa3
--- /dev/null
+++ b/dlls/winehaiku.drv/window.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#define thread_info haiku_thread_info
+#include <Application.h>
+#include <Window.h>
+#include <Bitmap.h>
+#include <OS.h>
+#include <locks.h>
+#undef thread_info
+
+extern "C" {
+#include "haikudrv.h"
+}
+#undef GetMonitorInfo
+
+class WineView: public BView {
+private:
+	HWND fHwnd;
+	struct haikudrv_thread_data *fData;
+	BBitmap *fBitmap;
+	uint32 fOldMouseBtns;
+
+public:
+	WineView(HWND hwnd, struct haikudrv_thread_data *data, BRect frame, const char *name);
+	void UpdateBitmap(BBitmap *bitmap, BRect dirty);
+	void MessageReceived(BMessage *msg);
+
+};
+
+class WineWindow: public BWindow {
+private:
+	WineView *fView;
+	HWND fHwnd;
+	struct haikudrv_thread_data *fData;
+	
+public:
+	mutex fCreateMutex;
+	window_surface *fSurface;
+	bool fSendResizeEvents;
+	bool fInDestroy;
+	RECT fNonClient;
+	//HANDLE fEvent;
+
+	WineWindow(HWND hwnd, struct haikudrv_thread_data *data, BRect frame);
+	virtual ~WineWindow();
+
+	bool QuitRequested() override;
+
+	void FrameMoved(BPoint newPosition) override;
+	void FrameResized(float newWidth, float newHeight) override;
+
+	HWND Handle() {return fHwnd;}
+	WineView *View() {return fView;}
+};
+
+class WineApplication: public BApplication {
+public:
+	WineApplication();
+};
+
+
+WineWindow* HaikuThisWindow(HWND hwnd, bool create = true);
-- 
2.30.2


From 084d7361e7c331d191d3b523a65f5af0f7070767 Mon Sep 17 00:00:00 2001
From: X512 <danger_mail@list.ru>
Date: Thu, 20 Jan 2022 22:31:14 +0900
Subject: haiku: update

---
 dlls/ntdll/unix/signal_x86_64.c | 64 +++++++++++++++++++++++++++++++--
 dlls/ntdll/unix/virtual.c       |  7 ++++
 dlls/winex11.drv/keyboard.c     |  4 +--
 dlls/winex11.drv/x11drv_main.c  |  3 +-
 dlls/ws2_32/unixlib.c           |  1 +
 programs/winedbg/winedbg.c      |  2 ++
 server/fd.c                     |  1 +
 server/signal.c                 |  3 ++
 tools/winegcc/winegcc.c         |  3 ++
 9 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 957f796444b..063892046e1 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -254,7 +254,7 @@ __ASM_GLOBAL_FUNC( alloc_fs_sel,
 #define R13_sig(context)     ((context)->uc_mcontext.r13)
 #define R14_sig(context)     ((context)->uc_mcontext.r14)
 #define R15_sig(context)     ((context)->uc_mcontext.r15)
-#define CS_sig(context)      NULL
+#define CS_sig(context)      cs64_sel
 #define FS_sig(context)      NULL
 #define GS_sig(context)      NULL
 #define EFL_sig(context)     ((context)->uc_mcontext.rflags)
@@ -2577,6 +2577,46 @@ static BOOL handle_syscall_trap( ucontext_t *sigcontext )
 }
 
 
+NTSTATUS static LdrFindEntryForAddress2( const void *addr, PLDR_DATA_TABLE_ENTRY *pmod )
+{
+    PLIST_ENTRY mark, entry;
+    PLDR_DATA_TABLE_ENTRY mod;
+
+    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
+    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
+    {
+        mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
+        if (mod->DllBase <= addr &&
+            (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage)
+        {
+            *pmod = mod;
+            return STATUS_SUCCESS;
+        }
+    }
+    return STATUS_NO_MORE_ENTRIES;
+}
+
+static void WriteRtlString(UNICODE_STRING str)
+{
+	for (int i = 0; i < str.Length; i++) {
+		printf("%c", str.Buffer[i]);
+	}
+}
+
+static void WriteModuleName(addr_t address)
+{
+	HMODULE hModule = NULL;
+	PLDR_DATA_TABLE_ENTRY pmod = NULL;
+	LdrFindEntryForAddress2(
+		(void*)address,
+		&pmod
+	);
+	hModule = pmod == NULL ? NULL : pmod->DllBase;
+	printf("  hModule: %p\n", hModule);
+	if (hModule != NULL)
+	printf("  BaseDllName: %s\n", debugstr_w(pmod->BaseDllName.Buffer)); printf("\n");
+}
+
 /**********************************************************************
  *		segv_handler
  *
@@ -2588,11 +2628,16 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
     struct xcontext context;
     ucontext_t *ucontext = sigcontext;
     printf("segv_handler\n");
+    printf("&segv_handler: %p\n", &segv_handler);
+    printf("pKiUserExceptionDispatcher: %p\n", pKiUserExceptionDispatcher);
+    printf("  thread: %" PRId32 "\n", find_thread(NULL));
     printf("  IP: %#" PRIx64 "\n", RIP_sig(ucontext));
     printf("  SP: %#" PRIx64 "\n", RSP_sig(ucontext));
     printf("  FP: %#" PRIx64 "\n", RBP_sig(ucontext));
     printf("  address: %#" PRIx64 "\n", siginfo->si_addr);
-    _exit(1);
+    WriteModuleName(RIP_sig(ucontext));
+    fgetc(stdin);
+    //_exit(1);
 
     rec.ExceptionAddress = (void *)RIP_sig(ucontext);
     save_context( &context, sigcontext );
@@ -2781,6 +2826,18 @@ static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
  */
 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 {
+    ucontext_t *ucontext = sigcontext;
+    printf("abrt_handler\n");
+    printf("&abrt_handler: %p\n", &segv_handler);
+    printf("pKiUserExceptionDispatcher: %p\n", pKiUserExceptionDispatcher);
+    printf("  thread: %" PRId32 "\n", find_thread(NULL));
+    printf("  IP: %#" PRIx64 "\n", RIP_sig(ucontext));
+    printf("  SP: %#" PRIx64 "\n", RSP_sig(ucontext));
+    printf("  FP: %#" PRIx64 "\n", RBP_sig(ucontext));
+    printf("  address: %#" PRIx64 "\n", siginfo->si_addr);
+    //fgetc(stdin);
+    //_exit(1);
+
     EXCEPTION_RECORD rec = { EXCEPTION_WINE_ASSERTION, EH_NONCONTINUABLE };
 
     setup_exception( sigcontext, &rec );
@@ -2807,7 +2864,7 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext )
 static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
 {
     struct xcontext context;
-
+//#ifndef __HAIKU__
     if (is_inside_syscall( ucontext ))
     {
         DECLSPEC_ALIGN(64) XSTATE xs;
@@ -2824,6 +2881,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
         wait_suspend( &context.c );
         restore_context( &context, ucontext );
     }
+//#endif
 }
 
 
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 5873a3e2335..ca6bb6caceb 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -22,6 +22,12 @@
 #pragma makedep unix
 #endif
 
+#define cpu_info haiku_cpu_info
+#if defined(__HAIKU__)
+# include <OS.h>
+#endif
+#undef cpu_info
+
 #include "config.h"
 
 #include <assert.h>
@@ -3164,6 +3170,7 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI
 
     if (!reserve_size) reserve_size = main_image_info.MaximumStackSize;
     if (!commit_size) commit_size = main_image_info.CommittedStackSize;
+    commit_size = reserve_size;
 
     size = max( reserve_size, commit_size );
     if (size < 1024 * 1024) size = 1024 * 1024;  /* Xlib needs a large stack */
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index c6eab6f5cfa..9086a9db8cb 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -2132,7 +2132,7 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
   int keyi;
   KeySym keys;
   char *name;
-
+#if 0
   scanCode = lParam >> 16;
   scanCode &= 0x1ff;  /* keep "extended-key" flag with code */
 
@@ -2232,7 +2232,7 @@ INT CDECL X11DRV_GetKeyNameText(LONG lParam, LPWSTR lpBuffer, INT nSize)
           return rc;
       }
   }
-
+#endif
   /* Finally issue WARN for unknown keys   */
 
   LeaveCriticalSection( &kbd_section );
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index e5592184337..d1b1cd362c0 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -624,10 +624,11 @@ static BOOL process_attach(void)
     X11DRV_XComposite_Init();
 #endif
     X11DRV_XInput2_Init();
-
+/*
 #ifdef HAVE_XKB
     if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL );
 #endif
+*/
     X11DRV_InitKeyboard( gdi_display );
     if (use_xim) use_xim = X11DRV_InitXIM( input_style );
 
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c
index 4b9274bf867..d46ac996968 100644
--- a/dlls/ws2_32/unixlib.c
+++ b/dlls/ws2_32/unixlib.c
@@ -90,6 +90,7 @@
 # include <linux/irda.h>
 # define HAS_IRDA
 #endif
+#define HAVE_GETADDRINFO
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c
index 659ca364544..3a503dccaf3 100644
--- a/programs/winedbg/winedbg.c
+++ b/programs/winedbg/winedbg.c
@@ -621,6 +621,8 @@ static void restart_if_wow64(void)
 
 int main(int argc, char** argv)
 {
+    return 0;
+
     int 	        retv = 0;
     HANDLE              hFile = INVALID_HANDLE_VALUE;
     enum dbg_start      ds;
diff --git a/server/fd.c b/server/fd.c
index 1a0840f4113..3b47269aef7 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1001,6 +1001,7 @@ void main_loop(void)
 
         if (!active_users) break;  /* last user removed by a timeout */
 
+        //printf("poll(%d, %d), active_users: %d\n", nb_users, timeout, active_users);
         ret = poll( pollfd, nb_users, timeout );
         set_current_time();
 
diff --git a/server/signal.c b/server/signal.c
index 05dafe154f5..c620d7c2af3 100644
--- a/server/signal.c
+++ b/server/signal.c
@@ -259,6 +259,7 @@ int watchdog_triggered(void)
 
 static int core_dump_disabled( void )
 {
+#if 0
     int r = 0;
 #ifdef RLIMIT_CORE
     struct rlimit lim;
@@ -266,6 +267,8 @@ static int core_dump_disabled( void )
     r = !getrlimit(RLIMIT_CORE, &lim) && (lim.rlim_cur == 0);
 #endif
     return r;
+#endif
+    return 0;
 }
 
 void init_signals(void)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c
index e8457e46643..0626329837b 100644
--- a/tools/winegcc/winegcc.c
+++ b/tools/winegcc/winegcc.c
@@ -1341,6 +1341,9 @@ static void build(struct options* opts)
     {
 	strarray_add(&link_args, "-lm");
 	strarray_add(&link_args, "-lc");
+#ifdef __HAIKU__
+	strarray_add(&link_args, "-lnetwork");
+#endif
     }
 
     if (libgcc) strarray_add(&link_args, libgcc);
-- 
2.30.2


From e63186126bd1bc120ae6f919f29dd5d68a9e17c9 Mon Sep 17 00:00:00 2001
From: X512 <danger_mail@list.ru>
Date: Tue, 25 Jan 2022 22:12:25 +0900
Subject: ntdll: register PE modules for Haiku

---
 dlls/ntdll/unix/virtual.c | 51 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index ca6bb6caceb..86778e158d3 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -22,14 +22,19 @@
 #pragma makedep unix
 #endif
 
+#include "config.h"
+
 #define cpu_info haiku_cpu_info
 #if defined(__HAIKU__)
 # include <OS.h>
+# include <private/system/image_defs.h>
+
+extern image_id _kern_register_image(extended_image_info *info, size_t size);
+extern status_t _kern_unregister_image(image_id id);
+
 #endif
 #undef cpu_info
 
-#include "config.h"
-
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -625,6 +630,47 @@ void release_builtin_module( void *module )
 }
 
 
+static void haiku_register_module( void *module, int fd, WCHAR *wpath )
+{
+	IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)module;
+	IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((char*)module + dos->e_lfanew);
+
+	struct stat stat;
+	fstat(fd, &stat);
+
+	extended_image_info info = {
+		.basic_info = {
+			.type = (true || (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) ? B_LIBRARY_IMAGE : B_APP_IMAGE,
+			.device = stat.st_dev,
+			.node = stat.st_ino,
+			.text = (uint8*)module + nt->OptionalHeader.BaseOfCode,
+			.data = (uint8*)module + nt->OptionalHeader.BaseOfCode + nt->OptionalHeader.SizeOfCode,
+			.text_size = nt->OptionalHeader.SizeOfCode,
+			.data_size = nt->OptionalHeader.SizeOfImage - nt->OptionalHeader.BaseOfCode,
+		},
+		.text_delta = (int64)module + nt->OptionalHeader.BaseOfCode - (int64)nt->OptionalHeader.ImageBase
+	};
+	ntdll_wcstoumbs(wpath, wcslen(wpath), info.basic_info.name, MAXPATHLEN, FALSE);
+
+	if (true || strstr(info.basic_info.name, ".so") != NULL)
+		return;
+/*
+	static const char builtin_signature[32] = "Wine builtin DLL";
+	if (memcmp( dos + 1, builtin_signature, sizeof(builtin_signature) ) == 0)
+		return;
+*/
+	for (size_t i = 0; info.basic_info.name[i] != '\0'; i++) {
+		if (info.basic_info.name[i] == '\\')
+			info.basic_info.name[i] = '/';
+	}
+	_kern_register_image(&info, sizeof(info));
+}
+
+static void haiku_unregister_module( void *module )
+{
+}
+
+
 /***********************************************************************
  *           get_builtin_so_handle
  */
@@ -2537,6 +2583,7 @@ static NTSTATUS virtual_map_image( HANDLE mapping, ACCESS_MASK access, void **ad
     if (status >= 0)
     {
         if (is_builtin) add_builtin_module( view->base, NULL );
+        haiku_register_module(view->base, unix_fd, filename);
         *addr_ptr = view->base;
         *size_ptr = size;
         VIRTUAL_DEBUG_DUMP_VIEW( view );
-- 
2.30.2


From 8300eac14bc52a462a1e03173590168801e6d8e7 Mon Sep 17 00:00:00 2001
From: X512 <danger_mail@list.ru>
Date: Tue, 25 Jan 2022 22:13:57 +0900
Subject: winehaiku.drv: update

---
 dlls/winehaiku.drv/window.cpp | 38 +++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/dlls/winehaiku.drv/window.cpp b/dlls/winehaiku.drv/window.cpp
index 18dcba70c69..41331e31c24 100644
--- a/dlls/winehaiku.drv/window.cpp
+++ b/dlls/winehaiku.drv/window.cpp
@@ -536,6 +536,16 @@ WineWindow* HaikuThisWindow(HWND hwnd, bool create)
 	return window;
 }
 
+static void HaikuRemoveWindow(HWND hwnd)
+{
+	BAutolock lock(be_app);
+	auto it = sWindows->find(hwnd);
+	if (it == sWindows->end()) {
+		ERR("hwnd %p not present in host window list\n", hwnd);
+	}
+	sWindows->erase(it);
+}
+
 
 //#pragma mark - window_surface
 
@@ -760,9 +770,16 @@ static BOOL is_window_managed( HWND hwnd, UINT swp_flags, const RECT *window_rec
 {
     DWORD style, ex_style;
 
+    return hwnd == GetAncestor(hwnd, GA_ROOT);
+
     /* child windows are not managed */
     style = GetWindowLongW( hwnd, GWL_STYLE );
-    if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) return FALSE;
+    if ((style & (WS_CHILD|WS_POPUP)) == WS_CHILD) {
+    	HWND hwndParent = GetParent(hwnd);
+    	if (hwndParent == GetDesktopWindow())
+    		return TRUE;
+    	return FALSE;
+    }
     return TRUE;
 
     /* activated windows are managed */
@@ -899,6 +916,7 @@ static void GetHaikuWindowFlags(
     }
     else if (ex_style & WS_EX_DLGMODALFRAME) {if (look == B_NO_BORDER_WINDOW_LOOK) look = B_MODAL_WINDOW_LOOK;}
     else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) {if (look == B_NO_BORDER_WINDOW_LOOK) look = B_MODAL_WINDOW_LOOK;}
+    else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_BORDER) {if (look == B_NO_BORDER_WINDOW_LOOK) look = B_BORDERED_WINDOW_LOOK;}
 }
 
 
@@ -951,6 +969,7 @@ void CDECL HAIKUDRV_DestroyWindow( HWND hwnd )
 	wnd->fInDestroy = true;
 	BMessenger(wnd).SendMessage(B_QUIT_REQUESTED);
 	wnd->Unlock();
+	HaikuRemoveWindow(hwnd);
 }
 
 
@@ -1043,7 +1062,7 @@ BOOL CDECL HAIKUDRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update )
 void CDECL HAIKUDRV_SetCapture( HWND hwnd, UINT flags )
 {
 	FIXME("(%ld, %x): stub\n", (long)hwnd, flags);
-	return;
+	hwnd = GetAncestor(hwnd, GA_ROOT);
 	if (hwnd == sCaptureWnd) return;
 	WineWindow* prevWnd = HaikuThisWindow(sCaptureWnd, false);
 	if (prevWnd != NULL) {
@@ -1051,7 +1070,8 @@ void CDECL HAIKUDRV_SetCapture( HWND hwnd, UINT flags )
 		prevWnd->View()->SetEventMask(0);
 		prevWnd->Unlock();
 	}
-	WineWindow* nextWnd = HaikuThisWindow(hwnd, false);
+	sCaptureWnd = hwnd;
+	WineWindow* nextWnd = HaikuThisWindow(sCaptureWnd, false);
 	if (nextWnd != NULL) {
 		nextWnd->Lock();
 		nextWnd->View()->SetEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS);
@@ -1077,13 +1097,15 @@ BOOL CDECL HAIKUDRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_fl
                                      struct window_surface **surface )
 {
 	//FIXME("(%ld): stub\n", (long)hwnd);
-	ERR("(%ld)\n", (long)hwnd);
+	char className[256];
+	GetClassNameA(hwnd, className, 256);
+	//ERR("(%ld), class: \"%s\"\n", (long)hwnd, className);
 	
 	if (hwnd == GetDesktopWindow()) return TRUE;
 	if (!is_window_managed( hwnd, swp_flags, window_rect )) return TRUE;
 	
-	ERR("window_rect: (%d, %d, %d, %d)\n", window_rect->left, window_rect->top, window_rect->right, window_rect->bottom);
-	ERR("client_rect: (%d, %d, %d, %d)\n", client_rect->left, client_rect->top, client_rect->right, client_rect->bottom);
+	//ERR("window_rect: (%d, %d, %d, %d)\n", window_rect->left, window_rect->top, window_rect->right, window_rect->bottom);
+	//ERR("client_rect: (%d, %d, %d, %d)\n", client_rect->left, client_rect->top, client_rect->right, client_rect->bottom);
 	
 	DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
 	DWORD exStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
@@ -1133,11 +1155,11 @@ void CDECL HAIKUDRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_fla
                                     const RECT *visible_rect, const RECT *valid_rects,
                                     struct window_surface *surface )
 {
-	ERR("(%ld)\n", (long)hwnd);
+	//ERR("(%ld)\n", (long)hwnd);
   WineWindow *window = HaikuThisWindow(hwnd, false);
   if (window == NULL) return;
 
- 	ERR("(%p, swp_flags: %x)\n", hwnd, swp_flags);
+ 	//ERR("(%p, swp_flags: %x)\n", hwnd, swp_flags);
 
   DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
   DWORD exStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
-- 
2.30.2

