Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback.
This structure was being defined redundantly in multiple places. It has been moved to a public header where everyone can access it.
pktdef.h, which was never used at all, has been removed. --- dlls/winex11.drv/wintab.c | 17 --- dlls/wintab32/wintab_internal.h | 17 --- include/Makefile.in | 1 - include/pktdef.h | 248 -------------------------------- include/wintab.h | 19 ++- 5 files changed, 17 insertions(+), 285 deletions(-) delete mode 100644 include/pktdef.h
diff --git a/dlls/winex11.drv/wintab.c b/dlls/winex11.drv/wintab.c index 331601c3325..ef9bbc6be45 100644 --- a/dlls/winex11.drv/wintab.c +++ b/dlls/winex11.drv/wintab.c @@ -233,23 +233,6 @@ typedef struct tagWTI_DEVICES_INFO * linux wacom lists all the known values and this isn't one of them */ #define CSR_TYPE_OTHER 0x000
-typedef struct tagWTPACKET { - HCTX pkContext; - UINT pkStatus; - LONG pkTime; - WTPKT pkChanged; - UINT pkSerialNumber; - UINT pkCursor; - DWORD pkButtons; - DWORD pkX; - DWORD pkY; - DWORD pkZ; - UINT pkNormalPressure; - UINT pkTangentPressure; - ORIENTATION pkOrientation; - ROTATION pkRotation; /* 1.1 */ -} WTPACKET, *LPWTPACKET; -
#ifdef SONAME_LIBXI
diff --git a/dlls/wintab32/wintab_internal.h b/dlls/wintab32/wintab_internal.h index 18c64bfe700..3b31d021f66 100644 --- a/dlls/wintab32/wintab_internal.h +++ b/dlls/wintab32/wintab_internal.h @@ -116,23 +116,6 @@ typedef struct tagWTI_EXTENSIONS_INFO */ } WTI_EXTENSIONS_INFO, *LPWTI_EXTENSIONS_INFO;
-typedef struct tagWTPACKET { - HCTX pkContext; - UINT pkStatus; - LONG pkTime; - WTPKT pkChanged; - UINT pkSerialNumber; - UINT pkCursor; - DWORD pkButtons; - DWORD pkX; - DWORD pkY; - DWORD pkZ; - UINT pkNormalPressure; - UINT pkTangentPressure; - ORIENTATION pkOrientation; - ROTATION pkRotation; /* 1.1 */ -} WTPACKET, *LPWTPACKET; - typedef struct tagOPENCONTEXT { HCTX handle; diff --git a/include/Makefile.in b/include/Makefile.in index 9578c557af7..b9d2f8416fa 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -590,7 +590,6 @@ SOURCES = \ perflib.h \ perhist.idl \ physicalmonitorenumerationapi.h \ - pktdef.h \ poppack.h \ powrprof.h \ prntvpt.h \ diff --git a/include/pktdef.h b/include/pktdef.h deleted file mode 100644 index a1622062658..00000000000 --- a/include/pktdef.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 1991-1998 by LCS/Telegraphics - * Copyright (C) 2002 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_PKTDEF_H -#define __WINE_PKTDEF_H - -/*********************************************************************** - * How to use pktdef.h: - * - * 1. Include wintab.h - * 2. if using just one packet format: - * a. Define PACKETDATA and PACKETMODE as or'ed combinations of WTPKT bits - * (use the PK_* identifiers). - * b. Include pktdef.h. - * c. The generated structure typedef will be called PACKET. Use PACKETDATA - * and PACKETMODE to fill in the LOGCONTEXT structure. - * 3. If using multiple packet formats, for each one: - * a. Define PACKETNAME. Its text value will be a prefix for this packet's - * parameters and names. - * b. Define <PACKETNAME>PACKETDATA and <PACKETNAME>PACKETMODE similar to - * 2.a. above. - * c. Include pktdef.h. - * d. The generated structure typedef will be called - * <PACKETNAME>PACKET. Compare with 2.c. above and example #2 below. - * 4. If using extension packet data, do the following additional steps - * for each extension: - * a. Before including pktdef.h, define <PACKETNAME>PACKET<EXTENSION> - * as either PKEXT_ABSOLUTE or PKEXT_RELATIVE. - * b. The generated structure typedef will contain a field for the - * extension data. - * c. Scan the WTI_EXTENSION categories to find the extension's - * packet mask bit. - * d. OR the packet mask bit with <PACKETNAME>PACKETDATA and use the - * result in the lcPktData field of the LOGCONTEXT structure. - * e. If <PACKETNAME>PACKET<EXTENSION> was PKEXT_RELATIVE, OR the - * packet mask bit with <PACKETNAME>PACKETMODE and use the result - * in the lcPktMode field of the LOGCONTEXT structure. - * - * - * Example #1. -- single packet format - * - * #include <wintab.h> - * #define PACKETDATA PK_X | PK_Y | PK_BUTTONS /@ x, y, buttons @/ - * #define PACKETMODE PK_BUTTONS /@ buttons relative mode @/ - * #include <pktdef.h> - * ... - * lc.lcPktData = PACKETDATA; - * lc.lcPktMode = PACKETMODE; - * - * Example #2. -- multiple formats - * - * #include <wintab.h> - * #define PACKETNAME MOE - * #define MOEPACKETDATA PK_X | PK_Y | PK_BUTTONS /@ x, y, buttons @/ - * #define MOEPACKETMODE PK_BUTTONS /@ buttons relative mode @/ - * #include <pktdef.h> - * #define PACKETNAME LARRY - * #define LARRYPACKETDATA PK_Y | PK_Z | PK_BUTTONS /@ y, z, buttons @/ - * #define LARRYPACKETMODE PK_BUTTONS /@ buttons relative mode @/ - * #include <pktdef.h> - * #define PACKETNAME CURLY - * #define CURLYPACKETDATA PK_X | PK_Z | PK_BUTTONS /@ x, z, buttons @/ - * #define CURLYPACKETMODE PK_BUTTONS /@ buttons relative mode @/ - * #include <pktdef.h> - * ... - * lcMOE.lcPktData = MOEPACKETDATA; - * lcMOE.lcPktMode = MOEPACKETMODE; - * ... - * lcLARRY.lcPktData = LARRYPACKETDATA; - * lcLARRY.lcPktMode = LARRYPACKETMODE; - * ... - * lcCURLY.lcPktData = CURLYPACKETDATA; - * lcCURLY.lcPktMode = CURLYPACKETMODE; - * - * Example #3. -- extension packet data "XFOO". - * - * #include <wintab.h> - * #define PACKETDATA PK_X | PK_Y | PK_BUTTONS /@ x, y, buttons @/ - * #define PACKETMODE PK_BUTTONS /@ buttons relative mode @/ - * #define PACKETXFOO PKEXT_ABSOLUTE /@ XFOO absolute mode @/ - * #include <pktdef.h> - * ... - * UINT ScanExts(UINT wTag) - * { - * UINT i; - * UINT wScanTag; - * - * /@ scan for wTag's info category. @/ - * for (i = 0; WTInfo(WTI_EXTENSIONS + i, EXT_TAG, &wScanTag); i++) { - * if (wTag == wScanTag) { - * /@ return category offset from WTI_EXTENSIONS. @/ - * return i; - * } - * } - * /@ return error code. @/ - * return 0xFFFF; - * } - * ... - * lc.lcPktData = PACKETDATA; - * lc.lcPktMode = PACKETMODE; - * #ifdef PACKETXFOO - * categoryXFOO = ScanExts(WTX_XFOO); - * WTInfo(WTI_EXTENSIONS + categoryXFOO, EXT_MASK, &maskXFOO); - * lc.lcPktData |= maskXFOO; - * #if PACKETXFOO == PKEXT_RELATIVE - * lc.lcPktMode |= maskXFOO; - * #endif - * #endif - * WTOpen(hWnd, &lc, TRUE); - */ - -#ifdef __cplusplus -extern "C" { -#endif /* defined(__cplusplus) */ - -#ifndef PACKETNAME -/* if no packet name prefix */ -# define __PFX(x) x -# define __IFX(x,y) x ## y -#else -/* add prefixes and infixes to packet format names */ -# define __PFX(x) __PFX2(PACKETNAME,x) -# define __PFX2(p,x) __PFX3(p,x) -# define __PFX3(p,x) p ## x -# define __IFX(x,y) __IFX2(x,PACKETNAME,y) -# define __IFX2(x,i,y) __IFX3(x,i,y) -# define __IFX3(x,i,y) x ## i ## y -#endif - -#define __SFX2(x,s) __SFX3(x,s) -#define __SFX3(x,s) x ## s - -#define __TAG __IFX(tag,PACKET) -#define __TYPES \ - __PFX(PACKET), * __IFX(P,PACKET), \ - * __IFX(NP,PACKET), * __IFX(LP,PACKET) - -#define __DATA (__PFX(PACKETDATA)) -#define __MODE (__PFX(PACKETMODE)) -#define __EXT(x) __SFX2(__PFX(PACKET),x) - -typedef struct __TAG { -#if (__DATA & PK_CONTEXT) - HCTX pkContext; -#endif -#if (__DATA & PK_STATUS) - UINT pkStatus; -#endif -#if (__DATA & PK_TIME) - DWORD pkTime; -#endif -#if (__DATA & PK_CHANGED) - WTPKT pkChanged; -#endif -#if (__DATA & PK_SERIAL_NUMBER) - UINT pkSerialNumber; -#endif -#if (__DATA & PK_CURSOR) - UINT pkCursor; -#endif -#if (__DATA & PK_BUTTONS) - DWORD pkButtons; -#endif -#if (__DATA & PK_X) - LONG pkX; -#endif -#if (__DATA & PK_Y) - LONG pkY; -#endif -#if (__DATA & PK_Z) - LONG pkZ; -#endif -#if (__DATA & PK_NORMAL_PRESSURE) -# if (__MODE & PK_NORMAL_PRESSURE) - /* relative */ - int pkNormalPressure; -# else - /* absolute */ - UINT pkNormalPressure; -# endif -#endif -#if (__DATA & PK_TANGENT_PRESSURE) -# if (__MODE & PK_TANGENT_PRESSURE) - /* relative */ - int pkTangentPressure; -# else - /* absolute */ - UINT pkTangentPressure; -# endif -#endif -#if (__DATA & PK_ORIENTATION) - ORIENTATION pkOrientation; -#endif -#if (__DATA & PK_ROTATION) - ROTATION pkRotation; /* 1.1 */ -#endif - -#ifndef NOWTEXTENSIONS - /* extensions begin here. */ - -#if (__EXT(FKEYS) == PKEXT_RELATIVE) || (__EXT(FKEYS) == PKEXT_ABSOLUTE) - UINT pkFKeys; -#endif -#if (__EXT(TILT) == PKEXT_RELATIVE) || (__EXT(TILT) == PKEXT_ABSOLUTE) - TILT pkTilt; -#endif - -#endif - -} __TYPES; - -#undef PACKETNAME -#undef __TAG -#undef __TAG2 -#undef __TYPES -#undef __TYPES2 -#undef __DATA -#undef __MODE -#undef __PFX -#undef __PFX2 -#undef __PFX3 -#undef __IFX -#undef __IFX2 -#undef __IFX3 -#undef __SFX2 -#undef __SFX3 - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* defined(__cplusplus) */ - -#endif /* defined(__WINE_PKTDEF_H */ diff --git a/include/wintab.h b/include/wintab.h index d10371b0217..9f607bbe7ef 100644 --- a/include/wintab.h +++ b/include/wintab.h @@ -462,8 +462,6 @@ DECL_WINELIB_TYPE_AW(LPLOGCONTEXT) * EVENT DATA DEFS */
-/* For packet structure definition, see pktdef.h */ - /* packet status values */ #define TPS_PROXIMITY 0x0001 #define TPS_QUEUE_ERR 0x0002 @@ -493,6 +491,23 @@ typedef struct tagROTATION { /* 1.1 */ #define TBN_UP 1 #define TBN_DOWN 2
+typedef struct tagWTPACKET { + HCTX pkContext; + UINT pkStatus; + LONG pkTime; + WTPKT pkChanged; + UINT pkSerialNumber; + UINT pkCursor; + DWORD pkButtons; + DWORD pkX; + DWORD pkY; + DWORD pkZ; + UINT pkNormalPressure; + UINT pkTangentPressure; + ORIENTATION pkOrientation; + ROTATION pkRotation; /* 1.1 */ +} WTPACKET, *LPWTPACKET; + /*********************************************************************** * DEVICE CONFIG CONSTANTS */
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback. --- dlls/winex11.drv/wintab.c | 16 ++++++++-------- dlls/wintab32/context.c | 20 ++++++++++---------- dlls/wintab32/wintab32.c | 6 +++--- dlls/wintab32/wintab_internal.h | 6 +++--- include/wintab.h | 4 ++-- tools/winapi/win32.api | 2 +- 6 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/dlls/winex11.drv/wintab.c b/dlls/winex11.drv/wintab.c index ef9bbc6be45..a157d44807c 100644 --- a/dlls/winex11.drv/wintab.c +++ b/dlls/winex11.drv/wintab.c @@ -248,9 +248,9 @@ static int proximity_in_type; static int proximity_out_type;
static HWND hwndTabletDefault; -static WTPACKET gMsgPacket; +static PACKET gMsgPacket; static DWORD gSerial; -static WTPACKET last_packet; +static PACKET last_packet;
/* Reference: http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html * @@ -828,7 +828,7 @@ static int cursor_from_device(DWORD deviceid, LPWTI_CURSORS_INFO *cursorp) return -1; }
-static DWORD get_changed_state( WTPACKET *pkt) +static DWORD get_changed_state( PACKET *pkt) { DWORD change = 0;
@@ -870,7 +870,7 @@ static BOOL motion_event( HWND hwnd, XEvent *event ) if (curnum < 0) return FALSE;
- memset(&gMsgPacket,0,sizeof(WTPACKET)); + memset(&gMsgPacket,0,sizeof(PACKET));
TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd, (int) motion->deviceid, curnum);
@@ -902,7 +902,7 @@ static BOOL button_event( HWND hwnd, XEvent *event ) if (curnum < 0) return FALSE;
- memset(&gMsgPacket,0,sizeof(WTPACKET)); + memset(&gMsgPacket,0,sizeof(PACKET));
TRACE("Received tablet button %s event\n", (event->type == button_press_type)?"press":"release");
@@ -954,7 +954,7 @@ static BOOL proximity_event( HWND hwnd, XEvent *event ) if (curnum < 0) return FALSE;
- memset(&gMsgPacket,0,sizeof(WTPACKET)); + memset(&gMsgPacket,0,sizeof(PACKET));
/* Set cursor to inverted if cursor is the eraser */ gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); @@ -1078,7 +1078,7 @@ int CDECL X11DRV_AttachEventQueueToTablet(HWND hOwner) /*********************************************************************** * X11DRV_GetCurrentPacket (X11DRV.@) */ -int CDECL X11DRV_GetCurrentPacket(LPWTPACKET packet) +int CDECL X11DRV_GetCurrentPacket(LPPACKET packet) { *packet = gMsgPacket; return 1; @@ -1539,7 +1539,7 @@ int CDECL X11DRV_AttachEventQueueToTablet(HWND hOwner) /*********************************************************************** * GetCurrentPacket (X11DRV.@) */ -int CDECL X11DRV_GetCurrentPacket(LPWTPACKET packet) +int CDECL X11DRV_GetCurrentPacket(LPPACKET packet) { return 0; } diff --git a/dlls/wintab32/context.c b/dlls/wintab32/context.c index 58ba6b49074..af013073bc4 100644 --- a/dlls/wintab32/context.c +++ b/dlls/wintab32/context.c @@ -100,7 +100,7 @@ static const char* DUMPBITS(int x) return wine_dbg_sprintf("{%s}",buf); }
-static inline void DUMPPACKET(WTPACKET packet) +static inline void DUMPPACKET(PACKET packet) { TRACE("pkContext: %p pkStatus: 0x%x pkTime : 0x%lx pkChanged: 0x%lx pkSerialNumber: 0x%x pkCursor : %i pkButtons: %lx pkX: %li pkY: %li pkZ: %li pkNormalPressure: %i pkTangentPressure: %i pkOrientation: (%i,%i,%i) pkRotation: (%i,%i,%i)\n", packet.pkContext, packet.pkStatus, packet.pkTime, packet.pkChanged, packet.pkSerialNumber, @@ -183,7 +183,7 @@ static inline DWORD ScaleForContext(DWORD In, LONG InOrg, LONG InExt, LONG OutOr return MulDiv(abs(InExt) - (In - InOrg), abs(OutExt), abs(InExt)) + OutOrg; }
-LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd) +LPOPENCONTEXT AddPacketToContextQueue(LPPACKET packet, HWND hwnd) { LPOPENCONTEXT ptr=NULL;
@@ -274,7 +274,7 @@ static inline int CopyTabletData(LPVOID target, LPVOID src, INT size) }
static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial, - LPWTPACKET *pkt) + LPPACKET *pkt) { int loop; int index = -1; @@ -293,7 +293,7 @@ static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt, - LPWTPACKET wtp) + LPPACKET wtp) { LPBYTE ptr;
@@ -470,7 +470,7 @@ HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable) newcontext->ActiveCursor = -1; newcontext->QueueSize = 10; newcontext->PacketsQueued = 0; - newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10); + newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(PACKET)*10);
EnterCriticalSection(&csTablet); newcontext->handle = gTopContext++; @@ -598,7 +598,7 @@ int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts) if (limit < context->PacketsQueued) { memmove(context->PacketQueue, &context->PacketQueue[limit], - (context->PacketsQueued - (limit))*sizeof(WTPACKET)); + (context->PacketsQueued - (limit))*sizeof(PACKET)); } context->PacketsQueued -= limit; LeaveCriticalSection(&csTablet); @@ -615,7 +615,7 @@ BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt) { int rc = 0; LPOPENCONTEXT context; - LPWTPACKET wtp = NULL; + LPPACKET wtp = NULL;
TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
@@ -641,7 +641,7 @@ BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt) if ((rc+1) < context->QueueSize) { memmove(context->PacketQueue, &context->PacketQueue[rc+1], - (context->PacketsQueued - (rc+1))*sizeof(WTPACKET)); + (context->PacketsQueued - (rc+1))*sizeof(PACKET)); } context->PacketsQueued -= (rc+1); } @@ -990,7 +990,7 @@ int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd, /* remove read packets */ if ((end+1) < context->PacketsQueued) memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1], - (context->PacketsQueued - (end+1)) * sizeof (WTPACKET)); + (context->PacketsQueued - (end+1)) * sizeof (PACKET));
context->PacketsQueued -= ((end-bgn)+1); *lpNPkts = ((end-bgn)+1); @@ -1125,7 +1125,7 @@ BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts) }
context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0, - context->PacketQueue, sizeof(WTPACKET)*nPkts); + context->PacketQueue, sizeof(PACKET)*nPkts);
context->QueueSize = nPkts; LeaveCriticalSection(&csTablet); diff --git a/dlls/wintab32/wintab32.c b/dlls/wintab32/wintab32.c index b13c0573454..416398a2633 100644 --- a/dlls/wintab32/wintab32.c +++ b/dlls/wintab32/wintab32.c @@ -43,7 +43,7 @@ static CRITICAL_SECTION_DEBUG csTablet_debug = CRITICAL_SECTION csTablet = { &csTablet_debug, -1, 0, 0, 0, 0 };
int (CDECL *pLoadTabletInfo)(HWND hwnddefault) = NULL; -int (CDECL *pGetCurrentPacket)(LPWTPACKET packet) = NULL; +int (CDECL *pGetCurrentPacket)(LPPACKET packet) = NULL; int (CDECL *pAttachEventQueueToTablet)(HWND hOwner) = NULL; UINT (CDECL *pWTInfoW)(UINT wCategory, UINT nIndex, LPVOID lpOutput) = NULL;
@@ -143,7 +143,7 @@ static LRESULT WINAPI TABLET_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam,
case WT_PACKET: { - WTPACKET packet; + PACKET packet; LPOPENCONTEXT handler; if (pGetCurrentPacket) { @@ -158,7 +158,7 @@ static LRESULT WINAPI TABLET_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, } case WT_PROXIMITY: { - WTPACKET packet; + PACKET packet; LPOPENCONTEXT handler; if (pGetCurrentPacket) { diff --git a/dlls/wintab32/wintab_internal.h b/dlls/wintab32/wintab_internal.h index 3b31d021f66..09a5c5098f3 100644 --- a/dlls/wintab32/wintab_internal.h +++ b/dlls/wintab32/wintab_internal.h @@ -125,17 +125,17 @@ typedef struct tagOPENCONTEXT INT ActiveCursor; INT QueueSize; INT PacketsQueued; - LPWTPACKET PacketQueue; + LPPACKET PacketQueue; struct tagOPENCONTEXT *next; } OPENCONTEXT, *LPOPENCONTEXT;
int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam, LPARAM lParam, BOOL send_always) DECLSPEC_HIDDEN; -LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd) DECLSPEC_HIDDEN; +LPOPENCONTEXT AddPacketToContextQueue(LPPACKET packet, HWND hwnd) DECLSPEC_HIDDEN;
/* X11drv functions */ extern int (CDECL *pLoadTabletInfo)(HWND hwnddefault) DECLSPEC_HIDDEN; -extern int (CDECL *pGetCurrentPacket)(LPWTPACKET packet) DECLSPEC_HIDDEN; +extern int (CDECL *pGetCurrentPacket)(LPPACKET packet) DECLSPEC_HIDDEN; extern int (CDECL *pAttachEventQueueToTablet)(HWND hOwner) DECLSPEC_HIDDEN; extern UINT (CDECL *pWTInfoW)(UINT wCategory, UINT nIndex, LPVOID lpOutput) DECLSPEC_HIDDEN;
diff --git a/include/wintab.h b/include/wintab.h index 9f607bbe7ef..d1298b9c20b 100644 --- a/include/wintab.h +++ b/include/wintab.h @@ -491,7 +491,7 @@ typedef struct tagROTATION { /* 1.1 */ #define TBN_UP 1 #define TBN_DOWN 2
-typedef struct tagWTPACKET { +typedef struct tagPACKET { HCTX pkContext; UINT pkStatus; LONG pkTime; @@ -506,7 +506,7 @@ typedef struct tagWTPACKET { UINT pkTangentPressure; ORIENTATION pkOrientation; ROTATION pkRotation; /* 1.1 */ -} WTPACKET, *LPWTPACKET; +} PACKET, *LPPACKET;
/*********************************************************************** * DEVICE CONFIG CONSTANTS diff --git a/tools/winapi/win32.api b/tools/winapi/win32.api index 5f3dd85cc93..49116614a4b 100644 --- a/tools/winapi/win32.api +++ b/tools/winapi/win32.api @@ -5756,7 +5756,7 @@ LPPOINT LPRECT LPSIZE LPVOID -LPWTPACKET * +LPPACKET * MONITORENUMPROC PIXELFORMATDESCRIPTOR * POINT *
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback.
CopyTabletData has been renamed to TABLET_CopyData due to a name conflict and for consistency with other wintab32 functions. --- dlls/winex11.drv/wintab.c | 326 +++++++++++++++++--------------------- include/wintab.h | 48 +++++- 2 files changed, 188 insertions(+), 186 deletions(-)
diff --git a/dlls/winex11.drv/wintab.c b/dlls/winex11.drv/wintab.c index a157d44807c..5fc1e8089b8 100644 --- a/dlls/winex11.drv/wintab.c +++ b/dlls/winex11.drv/wintab.c @@ -203,37 +203,6 @@ typedef struct tagWTI_DEVICES_INFO } WTI_DEVICES_INFO, *LPWTI_DEVICES_INFO;
-/*********************************************************************** - * WACOM WINTAB EXTENSIONS TO SUPPORT CSR_TYPE - * In Wintab 1.2, a CSR_TYPE feature was added. This adds the - * ability to return a type of cursor on a tablet. - * Unfortunately, we cannot get the cursor type directly from X, - * and it is not specified directly anywhere. So we virtualize - * the type here. (This is unfortunate, the kernel module has - * the exact type, but we have no way of getting that module to - * pass us that type). - * - * Reference linuxwacom driver project wcmCommon.c function - * idtotype for a much larger list of CSR_TYPE. - * - * http://linuxwacom.cvs.sourceforge.net/linuxwacom/linuxwacom-prod/src/xdrv/wc... - * - * The WTI_CURSORS_INFO.TYPE data is supposed to be used like this: - * (cursor.TYPE & 0x0F06) == target_cursor_type - * Reference: Section Unique ID - * http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html - */ -#define CSR_TYPE_PEN 0x822 -#define CSR_TYPE_ERASER 0x82a -#define CSR_TYPE_MOUSE_2D 0x007 -#define CSR_TYPE_MOUSE_4D 0x094 -/* CSR_TYPE_OTHER is a special value! assumed no real world significance - * if a stylus type or eraser type eventually have this value - * it'll be a bug. As of 2008 05 21 we can be sure because - * linux wacom lists all the known values and this isn't one of them */ -#define CSR_TYPE_OTHER 0x000 - - #ifdef SONAME_LIBXI
#include <X11/Xlib.h> @@ -1085,17 +1054,6 @@ int CDECL X11DRV_GetCurrentPacket(LPPACKET packet) }
-static inline int CopyTabletData(LPVOID target, LPCVOID src, INT size) -{ - /* - * It is valid to call CopyTabletData with NULL. - * This handles the WTInfo() case where lpOutput is null. - */ - if(target != NULL) - memcpy(target,src,size); - return(size); -} - /*********************************************************************** * X11DRV_WTInfoW (X11DRV.@) */ @@ -1106,7 +1064,7 @@ UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) * lpOutput == NULL signifies the user only wishes * to find the size of the data. * NOTE: - * From now on use CopyTabletData to fill lpOutput. memcpy will break + * From now on use TABLET_CopyData to fill lpOutput. memcpy will break * the code. */ int rc = 0; @@ -1134,24 +1092,24 @@ UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) case IFC_WINTABID: { static const WCHAR driver[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0}; - rc = CopyTabletData(lpOutput, driver, (strlenW(driver) + 1) * sizeof(WCHAR)); + rc = TABLET_CopyData(lpOutput, driver, (strlenW(driver) + 1) * sizeof(WCHAR)); break; } case IFC_SPECVERSION: version = (0x01) | (0x01 << 8); - rc = CopyTabletData(lpOutput, &version,sizeof(WORD)); + rc = TABLET_CopyData(lpOutput, &version,sizeof(WORD)); break; case IFC_IMPLVERSION: version = (0x00) | (0x01 << 8); - rc = CopyTabletData(lpOutput, &version,sizeof(WORD)); + rc = TABLET_CopyData(lpOutput, &version,sizeof(WORD)); break; case IFC_NDEVICES: num = 1; - rc = CopyTabletData(lpOutput, &num,sizeof(num)); + rc = TABLET_CopyData(lpOutput, &num,sizeof(num)); break; case IFC_NCURSORS: num = gNumCursors; - rc = CopyTabletData(lpOutput, &num,sizeof(num)); + rc = TABLET_CopyData(lpOutput, &num,sizeof(num)); break; default: FIXME("WTI_INTERFACE unhandled index %i\n",nIndex); @@ -1168,144 +1126,144 @@ UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) if (0 == gNumCursors) rc = 0; else - rc = CopyTabletData(lpOutput, &gSysContext, + rc = TABLET_CopyData(lpOutput, &gSysContext, sizeof(LOGCONTEXTW)); break; case CTX_NAME: - rc = CopyTabletData(lpOutput, gSysContext.lcName, + rc = TABLET_CopyData(lpOutput, gSysContext.lcName, (strlenW(gSysContext.lcName)+1) * sizeof(WCHAR)); break; case CTX_OPTIONS: - rc = CopyTabletData(lpOutput, &gSysContext.lcOptions, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcOptions, + sizeof(UINT)); break; case CTX_STATUS: - rc = CopyTabletData(lpOutput, &gSysContext.lcStatus, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcStatus, + sizeof(UINT)); break; case CTX_LOCKS: - rc= CopyTabletData (lpOutput, &gSysContext.lcLocks, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcLocks, + sizeof(UINT)); break; case CTX_MSGBASE: - rc = CopyTabletData(lpOutput, &gSysContext.lcMsgBase, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcMsgBase, + sizeof(UINT)); break; case CTX_DEVICE: - rc = CopyTabletData(lpOutput, &gSysContext.lcDevice, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcDevice, + sizeof(UINT)); break; case CTX_PKTRATE: - rc = CopyTabletData(lpOutput, &gSysContext.lcPktRate, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcPktRate, + sizeof(UINT)); break; case CTX_PKTDATA: - rc = CopyTabletData(lpOutput, &gSysContext.lcPktData, - sizeof(WTPKT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcPktData, + sizeof(WTPKT)); break; case CTX_PKTMODE: - rc = CopyTabletData(lpOutput, &gSysContext.lcPktMode, - sizeof(WTPKT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcPktMode, + sizeof(WTPKT)); break; case CTX_MOVEMASK: - rc = CopyTabletData(lpOutput, &gSysContext.lcMoveMask, - sizeof(WTPKT)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcMoveMask, + sizeof(WTPKT)); break; case CTX_BTNDNMASK: - rc = CopyTabletData(lpOutput, &gSysContext.lcBtnDnMask, - sizeof(DWORD)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcBtnDnMask, + sizeof(DWORD)); break; case CTX_BTNUPMASK: - rc = CopyTabletData(lpOutput, &gSysContext.lcBtnUpMask, - sizeof(DWORD)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcBtnUpMask, + sizeof(DWORD)); break; case CTX_INORGX: - rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcInOrgX, + sizeof(LONG)); break; case CTX_INORGY: - rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcInOrgY, + sizeof(LONG)); break; case CTX_INORGZ: - rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgZ, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcInOrgZ, + sizeof(LONG)); break; case CTX_INEXTX: - rc = CopyTabletData(lpOutput, &gSysContext.lcInExtX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcInExtX, + sizeof(LONG)); break; case CTX_INEXTY: - rc = CopyTabletData(lpOutput, &gSysContext.lcInExtY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcInExtY, + sizeof(LONG)); break; case CTX_INEXTZ: - rc = CopyTabletData(lpOutput, &gSysContext.lcInExtZ, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcInExtZ, + sizeof(LONG)); break; case CTX_OUTORGX: - rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcOutOrgX, + sizeof(LONG)); break; case CTX_OUTORGY: - rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcOutOrgY, + sizeof(LONG)); break; case CTX_OUTORGZ: - rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgZ, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcOutOrgZ, + sizeof(LONG)); break; case CTX_OUTEXTX: - rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcOutExtX, + sizeof(LONG)); break; case CTX_OUTEXTY: - rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcOutExtY, + sizeof(LONG)); break; case CTX_OUTEXTZ: - rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtZ, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcOutExtZ, + sizeof(LONG)); break; case CTX_SENSX: - rc = CopyTabletData(lpOutput, &gSysContext.lcSensX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSensX, + sizeof(LONG)); break; case CTX_SENSY: - rc = CopyTabletData(lpOutput, &gSysContext.lcSensY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSensY, + sizeof(LONG)); break; case CTX_SENSZ: - rc = CopyTabletData(lpOutput, &gSysContext.lcSensZ, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSensZ, + sizeof(LONG)); break; case CTX_SYSMODE: - rc = CopyTabletData(lpOutput, &gSysContext.lcSysMode, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSysMode, + sizeof(LONG)); break; case CTX_SYSORGX: - rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSysOrgX, + sizeof(LONG)); break; case CTX_SYSORGY: - rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSysOrgY, + sizeof(LONG)); break; case CTX_SYSEXTX: - rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSysExtX, + sizeof(LONG)); break; case CTX_SYSEXTY: - rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSysExtY, + sizeof(LONG)); break; case CTX_SYSSENSX: - rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensX, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSysSensX, + sizeof(LONG)); break; case CTX_SYSSENSY: - rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensY, - sizeof(LONG)); + rc = TABLET_CopyData(lpOutput, &gSysContext.lcSysSensY, + sizeof(LONG)); break; default: FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex); @@ -1336,57 +1294,57 @@ UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) switch (nIndex) { case CSR_NAME: - rc = CopyTabletData(lpOutput, tgtcursor->NAME, - (strlenW(tgtcursor->NAME)+1) * sizeof(WCHAR)); + rc = TABLET_CopyData(lpOutput, tgtcursor->NAME, + (strlenW(tgtcursor->NAME)+1) * sizeof(WCHAR)); break; case CSR_ACTIVE: - rc = CopyTabletData(lpOutput,&tgtcursor->ACTIVE, - sizeof(BOOL)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->ACTIVE, + sizeof(BOOL)); break; case CSR_PKTDATA: - rc = CopyTabletData(lpOutput,&tgtcursor->PKTDATA, - sizeof(WTPKT)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->PKTDATA, + sizeof(WTPKT)); break; case CSR_BUTTONS: - rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONS, - sizeof(BYTE)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->BUTTONS, + sizeof(BYTE)); break; case CSR_BUTTONBITS: - rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONBITS, - sizeof(BYTE)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->BUTTONBITS, + sizeof(BYTE)); break; case CSR_BTNNAMES: FIXME("Button Names not returned correctly\n"); - rc = CopyTabletData(lpOutput,&tgtcursor->BTNNAMES, - tgtcursor->cchBTNNAMES*sizeof(WCHAR)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->BTNNAMES, + tgtcursor->cchBTNNAMES*sizeof(WCHAR)); break; case CSR_BUTTONMAP: - rc = CopyTabletData(lpOutput,tgtcursor->BUTTONMAP, - sizeof(BYTE)*32); + rc = TABLET_CopyData(lpOutput,tgtcursor->BUTTONMAP, + sizeof(BYTE)*32); break; case CSR_SYSBTNMAP: - rc = CopyTabletData(lpOutput,tgtcursor->SYSBTNMAP, - sizeof(BYTE)*32); + rc = TABLET_CopyData(lpOutput,tgtcursor->SYSBTNMAP, + sizeof(BYTE)*32); break; case CSR_NPBTNMARKS: - rc = CopyTabletData(lpOutput,tgtcursor->NPBTNMARKS, - sizeof(UINT)*2); + rc = TABLET_CopyData(lpOutput,tgtcursor->NPBTNMARKS, + sizeof(UINT)*2); break; case CSR_NPBUTTON: - rc = CopyTabletData(lpOutput,&tgtcursor->NPBUTTON, - sizeof(BYTE)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->NPBUTTON, + sizeof(BYTE)); break; case CSR_NPRESPONSE: FIXME("Not returning CSR_NPRESPONSE correctly\n"); rc = 0; break; case CSR_TPBUTTON: - rc = CopyTabletData(lpOutput,&tgtcursor->TPBUTTON, - sizeof(BYTE)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->TPBUTTON, + sizeof(BYTE)); break; case CSR_TPBTNMARKS: - rc = CopyTabletData(lpOutput,tgtcursor->TPBTNMARKS, - sizeof(UINT)*2); + rc = TABLET_CopyData(lpOutput,tgtcursor->TPBTNMARKS, + sizeof(UINT)*2); break; case CSR_TPRESPONSE: FIXME("Not returning CSR_TPRESPONSE correctly\n"); @@ -1396,26 +1354,26 @@ UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) { DWORD id; id = tgtcursor->PHYSID; - rc = CopyTabletData(lpOutput,&id,sizeof(DWORD)); + rc = TABLET_CopyData(lpOutput,&id,sizeof(DWORD)); } break; case CSR_MODE: - rc = CopyTabletData(lpOutput,&tgtcursor->MODE,sizeof(UINT)); + rc = TABLET_CopyData(lpOutput,&tgtcursor->MODE,sizeof(UINT)); break; case CSR_MINPKTDATA: - rc = CopyTabletData(lpOutput,&tgtcursor->MINPKTDATA, + rc = TABLET_CopyData(lpOutput,&tgtcursor->MINPKTDATA, sizeof(UINT)); break; case CSR_MINBUTTONS: - rc = CopyTabletData(lpOutput,&tgtcursor->MINBUTTONS, + rc = TABLET_CopyData(lpOutput,&tgtcursor->MINBUTTONS, sizeof(UINT)); break; case CSR_CAPABILITIES: - rc = CopyTabletData(lpOutput,&tgtcursor->CAPABILITIES, + rc = TABLET_CopyData(lpOutput,&tgtcursor->CAPABILITIES, sizeof(UINT)); break; case CSR_TYPE: - rc = CopyTabletData(lpOutput,&tgtcursor->TYPE, + rc = TABLET_CopyData(lpOutput,&tgtcursor->TYPE, sizeof(UINT)); break; default: @@ -1428,92 +1386,92 @@ UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) switch (nIndex) { case DVC_NAME: - rc = CopyTabletData(lpOutput,gSysDevice.NAME, - (strlenW(gSysDevice.NAME)+1) * sizeof(WCHAR)); + rc = TABLET_CopyData(lpOutput,gSysDevice.NAME, + (strlenW(gSysDevice.NAME)+1) * sizeof(WCHAR)); break; case DVC_HARDWARE: - rc = CopyTabletData(lpOutput,&gSysDevice.HARDWARE, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.HARDWARE, + sizeof(UINT)); break; case DVC_NCSRTYPES: - rc = CopyTabletData(lpOutput,&gSysDevice.NCSRTYPES, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.NCSRTYPES, + sizeof(UINT)); break; case DVC_FIRSTCSR: - rc = CopyTabletData(lpOutput,&gSysDevice.FIRSTCSR, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.FIRSTCSR, + sizeof(UINT)); break; case DVC_PKTRATE: - rc = CopyTabletData(lpOutput,&gSysDevice.PKTRATE, - sizeof(UINT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.PKTRATE, + sizeof(UINT)); break; case DVC_PKTDATA: - rc = CopyTabletData(lpOutput,&gSysDevice.PKTDATA, - sizeof(WTPKT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.PKTDATA, + sizeof(WTPKT)); break; case DVC_PKTMODE: - rc = CopyTabletData(lpOutput,&gSysDevice.PKTMODE, - sizeof(WTPKT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.PKTMODE, + sizeof(WTPKT)); break; case DVC_CSRDATA: - rc = CopyTabletData(lpOutput,&gSysDevice.CSRDATA, - sizeof(WTPKT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.CSRDATA, + sizeof(WTPKT)); break; case DVC_XMARGIN: - rc = CopyTabletData(lpOutput,&gSysDevice.XMARGIN, - sizeof(INT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.XMARGIN, + sizeof(INT)); break; case DVC_YMARGIN: - rc = CopyTabletData(lpOutput,&gSysDevice.YMARGIN, - sizeof(INT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.YMARGIN, + sizeof(INT)); break; case DVC_ZMARGIN: rc = 0; /* unsupported */ /* - rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN, - sizeof(INT)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.ZMARGIN, + sizeof(INT)); */ break; case DVC_X: - rc = CopyTabletData(lpOutput,&gSysDevice.X, - sizeof(AXIS)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.X, + sizeof(AXIS)); break; case DVC_Y: - rc = CopyTabletData(lpOutput,&gSysDevice.Y, - sizeof(AXIS)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.Y, + sizeof(AXIS)); break; case DVC_Z: rc = 0; /* unsupported */ /* - rc = CopyTabletData(lpOutput,&gSysDevice.Z, - sizeof(AXIS)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.Z, + sizeof(AXIS)); */ break; case DVC_NPRESSURE: - rc = CopyTabletData(lpOutput,&gSysDevice.NPRESSURE, - sizeof(AXIS)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.NPRESSURE, + sizeof(AXIS)); break; case DVC_TPRESSURE: rc = 0; /* unsupported */ /* - rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE, - sizeof(AXIS)); + rc = TABLET_CopyData(lpOutput,&gSysDevice.TPRESSURE, + sizeof(AXIS)); */ break; case DVC_ORIENTATION: - rc = CopyTabletData(lpOutput,gSysDevice.ORIENTATION, - sizeof(AXIS)*3); + rc = TABLET_CopyData(lpOutput,gSysDevice.ORIENTATION, + sizeof(AXIS)*3); break; case DVC_ROTATION: rc = 0; /* unsupported */ /* - rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION, - sizeof(AXIS)*3); + rc = TABLET_CopyData(lpOutput,&gSysDevice.ROTATION, + sizeof(AXIS)*3); */ break; case DVC_PNPID: - rc = CopyTabletData(lpOutput,gSysDevice.PNPID, - (strlenW(gSysDevice.PNPID)+1)*sizeof(WCHAR)); + rc = TABLET_CopyData(lpOutput,gSysDevice.PNPID, + (strlenW(gSysDevice.PNPID)+1)*sizeof(WCHAR)); break; default: FIXME("WTI_DEVICES unhandled index %i\n",nIndex); diff --git a/include/wintab.h b/include/wintab.h index d1298b9c20b..e758a52a174 100644 --- a/include/wintab.h +++ b/include/wintab.h @@ -794,10 +794,54 @@ BOOL WINAPI WTMgrCsrPressureBtnMarksEx(HMGR, UINT, UINT *, UINT *);
#endif
-#endif +/*********************************************************************** + * WACOM WINTAB EXTENSIONS TO SUPPORT CSR_TYPE + * In Wintab 1.2, a CSR_TYPE feature was added. This adds the + * ability to return a type of cursor on a tablet. + * Unfortunately, we cannot get the cursor type directly from X, + * and it is not specified directly anywhere. So we virtualize + * the type here. (This is unfortunate, the kernel module has + * the exact type, but we have no way of getting that module to + * pass us that type). + * + * Reference linuxwacom driver project wcmCommon.c function + * idtotype for a much larger list of CSR_TYPE. + * + * http://linuxwacom.cvs.sourceforge.net/linuxwacom/linuxwacom-prod/src/xdrv/wc... + * + * The WTI_CURSORS_INFO.TYPE data is supposed to be used like this: + * (cursor.TYPE & 0x0F06) == target_cursor_type + * Reference: Section Unique ID + * http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html + */ +#define CSR_TYPE_PEN 0x822 +#define CSR_TYPE_ERASER 0x82a +#define CSR_TYPE_MOUSE_2D 0x007 +#define CSR_TYPE_MOUSE_4D 0x094 +/* CSR_TYPE_OTHER is a special value! assumed no real world significance + * if a stylus type or eraser type eventually have this value + * it'll be a bug. As of 2008 05 21 we can be sure because + * linux wacom lists all the known values and this isn't one of them */ +#define CSR_TYPE_OTHER 0x000 + +/*********************************************************************** + * WINE HELPER FUNCTIONS + */ + +/* Helper for WTInfoW. It is valid to call WTInfoW with lpOutput == NULL, in + * which case it must return the size of the data without copying anything. + * This function handles that case. */ +static inline int TABLET_CopyData(LPVOID target, LPCVOID src, INT size) +{ + if(target != NULL) + memcpy(target,src,size); + return(size); +} + +#endif /* !defined(NOWTFUNCTIONS) */
#ifdef __cplusplus } /* extern "C" */ #endif /* defined(__cplusplus) */
-#endif /* defined(__WINE_WINTAB_H */ +#endif /* !defined(__WINE_WINTAB_H) */
Fix multimonitor support by trusting the driver's values.
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback.
x11drv correctly sets system extents to the values of SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN. Overwriting them is not only bad from a code cleanliness perspective, but it's also wrong, because the values of SM_CXSCREEN and SM_CYSCREEN break multimonitor support.
The Linux and the Mac drivers do not handle cursor flipping in the same way, so this code has been delegated to the respective drivers and wintab32 now translates packets exactly per specification. --- dlls/winex11.drv/wintab.c | 11 ++++++++--- dlls/wintab32/context.c | 35 --------------------------------- dlls/wintab32/wintab_internal.h | 2 +- 3 files changed, 9 insertions(+), 39 deletions(-)
diff --git a/dlls/winex11.drv/wintab.c b/dlls/winex11.drv/wintab.c index 5fc1e8089b8..c54a1d57102 100644 --- a/dlls/winex11.drv/wintab.c +++ b/dlls/winex11.drv/wintab.c @@ -831,6 +831,11 @@ static DWORD get_changed_state( PACKET *pkt) return change; }
+static inline DWORD flip_y( DWORD y ) +{ + return gSysContext.lcInExtY - y; +} + static BOOL motion_event( HWND hwnd, XEvent *event ) { XDeviceMotionEvent *motion = (XDeviceMotionEvent *)event; @@ -849,7 +854,7 @@ static BOOL motion_event( HWND hwnd, XEvent *event ) gMsgPacket.pkSerialNumber = gSerial++; gMsgPacket.pkCursor = curnum; gMsgPacket.pkX = motion->axis_data[0]; - gMsgPacket.pkY = motion->axis_data[1]; + gMsgPacket.pkY = flip_y(motion->axis_data[1]); gMsgPacket.pkOrientation.orAzimuth = figure_deg(motion->axis_data[3],motion->axis_data[4]); gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max (abs(motion->axis_data[3]), @@ -883,7 +888,7 @@ static BOOL button_event( HWND hwnd, XEvent *event ) gMsgPacket.pkCursor = curnum; if (button->axes_count > 0) { gMsgPacket.pkX = button->axis_data[0]; - gMsgPacket.pkY = button->axis_data[1]; + gMsgPacket.pkY = flip_y(button->axis_data[1]); gMsgPacket.pkOrientation.orAzimuth = figure_deg(button->axis_data[3],button->axis_data[4]); gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(button->axis_data[3]), abs(button->axis_data[4]))) @@ -932,7 +937,7 @@ static BOOL proximity_event( HWND hwnd, XEvent *event ) gMsgPacket.pkSerialNumber = gSerial++; gMsgPacket.pkCursor = curnum; gMsgPacket.pkX = proximity->axis_data[0]; - gMsgPacket.pkY = proximity->axis_data[1]; + gMsgPacket.pkY = flip_y(proximity->axis_data[1]); gMsgPacket.pkOrientation.orAzimuth = figure_deg(proximity->axis_data[3],proximity->axis_data[4]); gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(proximity->axis_data[3]), abs(proximity->axis_data[4]))) diff --git a/dlls/wintab32/context.c b/dlls/wintab32/context.c index af013073bc4..da465d180c7 100644 --- a/dlls/wintab32/context.c +++ b/dlls/wintab32/context.c @@ -219,15 +219,6 @@ LPOPENCONTEXT AddPacketToContextQueue(LPPACKET packet, HWND hwnd) ptr->context.lcInExtX, ptr->context.lcOutOrgX, ptr->context.lcOutExtX);
- /* flip the Y axis */ - if (ptr->context.lcOutExtY > 0) - packet->pkY = ptr->context.lcOutExtY - packet->pkY; - else if (ptr->context.lcOutExtY < 0) - { - int y = ptr->context.lcOutExtY + packet->pkY; - packet->pkY = abs(y); - } - DUMPPACKET(*packet);
if (tgt == ptr->QueueSize) @@ -379,25 +370,6 @@ static UINT WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode)
TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode);
- /* - * Handle system extents here, as we can use user32.dll code to set them. - */ - if(wCategory == WTI_DEFSYSCTX) - { - switch(nIndex) - { - case CTX_SYSEXTX: - if(lpOutput != NULL) - *(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN); - return sizeof(LONG); - case CTX_SYSEXTY: - if(lpOutput != NULL) - *(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN); - return sizeof(LONG); - /* No action, delegate to X11Drv */ - } - } - if (is_logcontext_category(wCategory) && nIndex == 0) { if (lpOutput) @@ -405,13 +377,6 @@ static UINT WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode) LOGCONTEXTW buf; pWTInfoW(wCategory, nIndex, &buf);
- /* Handle system extents here, as we can use user32.dll code to set them */ - if(wCategory == WTI_DEFSYSCTX) - { - buf.lcSysExtX = GetSystemMetrics(SM_CXSCREEN); - buf.lcSysExtY = GetSystemMetrics(SM_CYSCREEN); - } - if (bUnicode) memcpy(lpOutput, &buf, sizeof(buf)); else diff --git a/dlls/wintab32/wintab_internal.h b/dlls/wintab32/wintab_internal.h index 09a5c5098f3..2ee59941faf 100644 --- a/dlls/wintab32/wintab_internal.h +++ b/dlls/wintab32/wintab_internal.h @@ -133,7 +133,7 @@ int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam, LPARAM lParam, BOOL send_always) DECLSPEC_HIDDEN; LPOPENCONTEXT AddPacketToContextQueue(LPPACKET packet, HWND hwnd) DECLSPEC_HIDDEN;
-/* X11drv functions */ +/* Display driver functions */ extern int (CDECL *pLoadTabletInfo)(HWND hwnddefault) DECLSPEC_HIDDEN; extern int (CDECL *pGetCurrentPacket)(LPPACKET packet) DECLSPEC_HIDDEN; extern int (CDECL *pAttachEventQueueToTablet)(HWND hOwner) DECLSPEC_HIDDEN;
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback.
Notes: - Updated documentation URL, the old one was broken. - Categories support negative indices. - Scaling uses Org+abs(Ext)-1, not Org+abs(Ext). - WT_PROXIMITY does not generate packets. - No data should be copied when WTInfoT returns 0. - Removing packets from the queue should only remove packets that actually exist, not the entire length of the buffer. - Packets with the same serial should be ignored. - There are a number of edge cases where the mapping requested by the application does not match the mapping of the system. Wine can't remap the tablet, but we can remap the coordinates so that the application works correctly. --- dlls/wintab32/context.c | 169 ++++++++++++++++++++++++++------ dlls/wintab32/wintab32.c | 14 +-- dlls/wintab32/wintab_internal.h | 1 + include/wintab.h | 26 +++++ 4 files changed, 171 insertions(+), 39 deletions(-)
diff --git a/dlls/wintab32/context.c b/dlls/wintab32/context.c index da465d180c7..5302fadfdca 100644 --- a/dlls/wintab32/context.c +++ b/dlls/wintab32/context.c @@ -38,7 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
/* * Documentation found at - * http://www.csl.sony.co.jp/projects/ar/restricted/wintabl.html + * https://developer-docs.wacom.com/intuos-cintiq-business-tablets/docs/wintab-... */
static LPOPENCONTEXT gOpenContexts; @@ -62,7 +62,8 @@ static void LOGCONTEXTWtoA(const LOGCONTEXTW *in, LOGCONTEXTA *out)
static BOOL is_logcontext_category(UINT wCategory) { - return wCategory == WTI_DEFSYSCTX || wCategory == WTI_DEFCONTEXT || wCategory == WTI_DDCTXS; + return wCategory == WTI_DEFSYSCTX || wCategory == WTI_DEFCONTEXT + || IS_WTI_DDCTXS_TYPE(wCategory) || IS_WTI_DSCTXS_TYPE(wCategory); }
static BOOL is_string_field(UINT wCategory, UINT nIndex) @@ -71,10 +72,11 @@ static BOOL is_string_field(UINT wCategory, UINT nIndex) return TRUE; if (is_logcontext_category(wCategory) && nIndex == CTX_NAME) return TRUE; - if ((wCategory >= WTI_CURSORS && wCategory <= WTI_CURSORS + 9) && - (nIndex == CSR_NAME || nIndex == CSR_BTNNAMES)) + if (IS_WTI_CURSORS_TYPE(wCategory) + && (nIndex == CSR_NAME || nIndex == CSR_BTNNAMES)) return TRUE; - if (wCategory == WTI_DEVICES && (nIndex == DVC_NAME || nIndex == DVC_PNPID)) + if (IS_WTI_DEVICES_TYPE(wCategory) + && (nIndex == DVC_NAME || nIndex == DVC_PNPID)) return TRUE; return FALSE; } @@ -175,12 +177,44 @@ int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam, return 0; }
+LPOPENCONTEXT FindContextForHwnd(HWND hwnd) +{ + LPOPENCONTEXT ptr = gOpenContexts; + + EnterCriticalSection(&csTablet); + while (ptr) + { + if (ptr->hwndOwner == hwnd && ptr->enabled) + break; + ptr = ptr->next; + } + LeaveCriticalSection(&csTablet); + return ptr; +} + +/* Scale point for tablet area. Org is offset. Ext is length. Negative extent + * indicates flipped coordinate system, but coordinates remain positive. + * (Org <= x < Org + abs(Ext)) */ static inline DWORD ScaleForContext(DWORD In, LONG InOrg, LONG InExt, LONG OutOrg, LONG OutExt) { - if (((InExt > 0 )&&(OutExt > 0)) || ((InExt<0) && (OutExt < 0))) - return MulDiv(In - InOrg, abs(OutExt), abs(InExt)) + OutOrg; + LONG AbsInExt = abs(InExt); + LONG AbsOutExt = abs(OutExt); + + if (AbsInExt <= 1 || AbsOutExt <= 1) + /* No dimensions */ + return 0; + + /* Largest representable value is 1 less than extent, we need to scale by + * that. This is the same way wintab does it. */ + AbsInExt--; + AbsOutExt--; + + if ((InExt < 0) == (OutExt < 0)) + /* Same sign, maintain direction */ + return MulDiv(In - InOrg, AbsOutExt, AbsInExt) + OutOrg; else - return MulDiv(abs(InExt) - (In - InOrg), abs(OutExt), abs(InExt)) + OutOrg; + /* Opposite signs, invert direction */ + return MulDiv(AbsInExt - (In - InOrg), AbsOutExt, AbsInExt) + OutOrg; }
LPOPENCONTEXT AddPacketToContextQueue(LPPACKET packet, HWND hwnd) @@ -204,20 +238,36 @@ LPOPENCONTEXT AddPacketToContextQueue(LPPACKET packet, HWND hwnd) }
tgt = ptr->PacketsQueued; + if (tgt > 0 && ptr->PacketQueue[tgt - 1].pkSerialNumber == packet->pkSerialNumber) + { + ptr = ptr->next; + continue; + + }
packet->pkContext = ptr->handle;
- /* translate packet data to the context */ + /* Translate packet data to the context */ packet->pkChanged = packet->pkChanged & ptr->context.lcPktData;
- /* Scale as per documentation */ - packet->pkY = ScaleForContext(packet->pkY, ptr->context.lcInOrgY, - ptr->context.lcInExtY, ptr->context.lcOutOrgY, - ptr->context.lcOutExtY); + packet->pkX = ScaleForContext(packet->pkX, + ptr->context.lcInOrgX, ptr->context.lcInExtX, + ptr->context.lcOutOrgX, ptr->context.lcOutExtX); + + packet->pkY = ScaleForContext(packet->pkY, + ptr->context.lcInOrgY, ptr->context.lcInExtY, + ptr->context.lcOutOrgY, ptr->context.lcOutExtY);
- packet->pkX = ScaleForContext(packet->pkX, ptr->context.lcInOrgX, - ptr->context.lcInExtX, ptr->context.lcOutOrgX, - ptr->context.lcOutExtX); + /* Clip values if outside of reporting range */ + if ((LONG)packet->pkX < ptr->context.lcOutOrgX) + packet->pkX = ptr->context.lcOutOrgX; + else if((LONG)packet->pkX >= ptr->context.lcOutOrgX + abs(ptr->context.lcOutExtX)) + packet->pkX = ptr->context.lcOutOrgX + abs(ptr->context.lcOutExtX) - 1; + + if ((LONG)packet->pkY < ptr->context.lcOutOrgY) + packet->pkY = ptr->context.lcOutOrgY; + else if((LONG)packet->pkY >= ptr->context.lcOutOrgY + abs(ptr->context.lcOutExtY)) + packet->pkY = ptr->context.lcOutOrgY + abs(ptr->context.lcOutExtY) - 1;
DUMPPACKET(*packet);
@@ -369,21 +419,27 @@ static UINT WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode) if (!LoadTablet()) return 0;
TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode); - if (is_logcontext_category(wCategory) && nIndex == 0) { - if (lpOutput) + if (pWTInfoW(wCategory, nIndex, NULL) == 0) { - LOGCONTEXTW buf; - pWTInfoW(wCategory, nIndex, &buf); - - if (bUnicode) - memcpy(lpOutput, &buf, sizeof(buf)); - else - LOGCONTEXTWtoA(&buf, lpOutput); + result = 0; } + else + { + if (lpOutput) + { + LOGCONTEXTW buf; + pWTInfoW(wCategory, nIndex, &buf); + + if (bUnicode) + memcpy(lpOutput, &buf, sizeof(buf)); + else + LOGCONTEXTWtoA(&buf, lpOutput); + }
- result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA); + result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA); + } } else if (is_string_field(wCategory, nIndex) && !bUnicode) { @@ -423,6 +479,9 @@ UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable) { LPOPENCONTEXT newcontext; + LONG inOrgX, inOrgY, inExtX, inExtY; + int sysOrgX, sysOrgY, sysExtX, sysExtY; + AXIS devAxX, devAxY;
if (!LoadTablet()) return 0;
@@ -433,9 +492,61 @@ HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable) newcontext->context = *lpLogCtx; newcontext->hwndOwner = hWnd; newcontext->ActiveCursor = -1; - newcontext->QueueSize = 10; + newcontext->QueueSize = 25; newcontext->PacketsQueued = 0; - newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(PACKET)*10); + newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(PACKET)*newcontext->QueueSize); + + /* Tablet area remapping is not supported. Ignore the incoming lcIn* values + * and use the system-provided values instead. */ + pWTInfoW(WTI_DEFSYSCTX, CTX_INORGX, &inOrgX); + pWTInfoW(WTI_DEFSYSCTX, CTX_INORGY, &inOrgY); + pWTInfoW(WTI_DEFSYSCTX, CTX_INEXTX, &inExtX); + pWTInfoW(WTI_DEFSYSCTX, CTX_INEXTY, &inExtY); + + /* According to Wacom's ScribbleDemo, the way to request raw tablet + * coordinates is to request an extent larger than the axis. */ + if (pWTInfoW(WTI_DEVICES + newcontext->context.lcDevice, DVC_X, &devAxX) > 0 + && pWTInfoW(WTI_DEVICES + newcontext->context.lcDevice, DVC_Y, &devAxY) > 0) + { + if (abs(newcontext->context.lcOutExtX) > devAxX.axMax - devAxX.axMin + 1 + || abs(newcontext->context.lcOutExtY) > devAxY.axMax - devAxY.axMin + 1) + { + newcontext->context.lcOutOrgX = inOrgX; + newcontext->context.lcOutExtX = (newcontext->context.lcOutExtX >= 0 + ? inExtX : -inExtX); + + newcontext->context.lcOutOrgY = inOrgY; + newcontext->context.lcOutExtY = (newcontext->context.lcOutExtY >= 0 + ? inExtY : -inExtY); + } + } + + /* wintab allows developers to customize the area of the screen that the + * tablet points to. Wine does NOT allow this, so fudge the input area as + * necessary to make it line up with the actual screen. */ + pWTInfoW(WTI_DEFSYSCTX, CTX_SYSORGX, &sysOrgX); + pWTInfoW(WTI_DEFSYSCTX, CTX_SYSORGY, &sysOrgY); + pWTInfoW(WTI_DEFSYSCTX, CTX_SYSEXTX, &sysExtX); + pWTInfoW(WTI_DEFSYSCTX, CTX_SYSEXTY, &sysExtY); + + newcontext->context.lcInOrgX = ScaleForContext(newcontext->context.lcSysOrgX, + sysOrgX, sysExtX, inOrgX, inExtX); + + /* Scale Y region from the bottom because the tablet is upside down */ + newcontext->context.lcInOrgY = ScaleForContext(newcontext->context.lcSysOrgY + abs(newcontext->context.lcSysExtY), + sysOrgY, -sysExtY, inOrgY, inExtY); + + newcontext->context.lcInExtX = MulDiv(abs(newcontext->context.lcSysExtX), + inExtX, sysExtX); + + newcontext->context.lcInExtY = MulDiv(abs(newcontext->context.lcSysExtY), + inExtY, sysExtY); + + if (memcmp(&newcontext->context, lpLogCtx, sizeof(newcontext->context)) != 0) + { + TRACE("Incoming context has been modified. Result:\n"); + DUMPCONTEXT(newcontext->context); + }
EnterCriticalSection(&csTablet); newcontext->handle = gTopContext++; @@ -603,7 +714,7 @@ BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt) if (lpPkt) TABLET_CopyPacketData(context ,lpPkt, wtp);
- if ((rc+1) < context->QueueSize) + if ((rc+1) < context->PacketsQueued) { memmove(context->PacketQueue, &context->PacketQueue[rc+1], (context->PacketsQueued - (rc+1))*sizeof(PACKET)); diff --git a/dlls/wintab32/wintab32.c b/dlls/wintab32/wintab32.c index 416398a2633..61a1917701a 100644 --- a/dlls/wintab32/wintab32.c +++ b/dlls/wintab32/wintab32.c @@ -158,16 +158,10 @@ static LRESULT WINAPI TABLET_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, } case WT_PROXIMITY: { - PACKET packet; - LPOPENCONTEXT handler; - if (pGetCurrentPacket) - { - pGetCurrentPacket(&packet); - handler = AddPacketToContextQueue(&packet,(HWND)wParam); - if (handler) - TABLET_PostTabletMessage(handler, WT_PROXIMITY, - (WPARAM)handler->handle, lParam, TRUE); - } + LPOPENCONTEXT handler = FindContextForHwnd((HWND)wParam); + if (handler) + TABLET_PostTabletMessage(handler, WT_PROXIMITY, + (WPARAM)handler->handle, lParam, TRUE); break; } } diff --git a/dlls/wintab32/wintab_internal.h b/dlls/wintab32/wintab_internal.h index 2ee59941faf..3f5302bf13c 100644 --- a/dlls/wintab32/wintab_internal.h +++ b/dlls/wintab32/wintab_internal.h @@ -131,6 +131,7 @@ typedef struct tagOPENCONTEXT
int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam, LPARAM lParam, BOOL send_always) DECLSPEC_HIDDEN; +LPOPENCONTEXT FindContextForHwnd(HWND hwnd) DECLSPEC_HIDDEN; LPOPENCONTEXT AddPacketToContextQueue(LPPACKET packet, HWND hwnd) DECLSPEC_HIDDEN;
/* Display driver functions */ diff --git a/include/wintab.h b/include/wintab.h index e758a52a174..8d95d1a97b8 100644 --- a/include/wintab.h +++ b/include/wintab.h @@ -838,6 +838,32 @@ static inline int TABLET_CopyData(LPVOID target, LPCVOID src, INT size) return(size); }
+/* Helpers for category. Though undocumented, negative indices are valid, and + * represent iterating the categories in reverse order. */ +#ifndef NOWTDEVICES +static inline BOOL IS_WTI_DEVICES_TYPE(UINT wCategory){ + return wCategory > WTI_DEVICES - 50 && wCategory <= WTI_DEVICES + 50; +} +#endif /* !defined(NOWTDEVICES) */ +#ifndef NOWTCURSORS +static inline BOOL IS_WTI_CURSORS_TYPE(UINT wCategory){ + return wCategory > WTI_CURSORS - 50 && wCategory <= WTI_CURSORS + 50; +} +#endif /* !defined(NOWTCURSORS) */ +#ifndef NOWTEXTENSIONS +static inline BOOL IS_WTI_EXTENSIONS_TYPE(UINT wCategory){ + return wCategory > WTI_EXTENSIONS - 50 && wCategory <= WTI_EXTENSIONS + 50; +} +#endif /* !defined(NOWTEXTENSIONS) */ +#ifndef NOWTDEFCONTEXT +static inline BOOL IS_WTI_DDCTXS_TYPE(UINT wCategory){ + return wCategory > WTI_DDCTXS - 50 && wCategory <= WTI_DDCTXS + 50; +} +static inline BOOL IS_WTI_DSCTXS_TYPE(UINT wCategory){ + return wCategory > WTI_DSCTXS - 50 && wCategory <= WTI_DSCTXS + 50; +} +#endif /* !defined(NOWTDEFCONTEXT) */ + #endif /* !defined(NOWTFUNCTIONS) */
#ifdef __cplusplus
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback. --- dlls/winemac.drv/Makefile.in | 3 +- dlls/winemac.drv/cocoa_wintab.h | 34 +++++++ dlls/winemac.drv/winemac.drv.spec | 6 ++ dlls/winemac.drv/wintab.c | 154 ++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 dlls/winemac.drv/cocoa_wintab.h create mode 100644 dlls/winemac.drv/wintab.c
diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in index da2e5eaf4c4..47b7c68feb3 100644 --- a/dlls/winemac.drv/Makefile.in +++ b/dlls/winemac.drv/Makefile.in @@ -21,7 +21,8 @@ C_SRCS = \ surface.c \ systray.c \ vulkan.c \ - window.c + window.c \ + wintab.c
OBJC_SRCS = \ cocoa_app.m \ diff --git a/dlls/winemac.drv/cocoa_wintab.h b/dlls/winemac.drv/cocoa_wintab.h new file mode 100644 index 00000000000..0fa20f6752c --- /dev/null +++ b/dlls/winemac.drv/cocoa_wintab.h @@ -0,0 +1,34 @@ +/* + * MACDRV Cocoa wintab declarations + * + * Copyright 2022 Elaine Lefler + * + * 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_MACDRV_COCOA_WINTAB_H +#define __WINE_MACDRV_COCOA_WINTAB_H + +#include "windef.h" +#include "wintab.h" + +/* Extents that shouldn't cause math problems */ +#define TABLET_WIDTH 0x40000000 +#define TABLET_HEIGHT 0x40000000 + +/* Shared device context */ +extern LOGCONTEXTW macdrv_tablet_ctx DECLSPEC_HIDDEN; + +#endif /* !defined(__WINE_MACDRV_COCOA_WINTAB_H) */ diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index b060d1cc2a6..13f5522242c 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -18,3 +18,9 @@ @ stdcall ImeToAsciiEx(long long ptr ptr long long) @ stdcall ImeUnregisterWord(wstr long wstr) @ stdcall NotifyIME(long long long long) + +# WinTab32 +@ cdecl AttachEventQueueToTablet(long) macdrv_AttachEventQueueToTablet +@ cdecl GetCurrentPacket(ptr) macdrv_GetCurrentPacket +@ cdecl LoadTabletInfo(long) macdrv_LoadTabletInfo +@ cdecl WTInfoW(long long ptr) macdrv_WTInfoW diff --git a/dlls/winemac.drv/wintab.c b/dlls/winemac.drv/wintab.c new file mode 100644 index 00000000000..fffae85f735 --- /dev/null +++ b/dlls/winemac.drv/wintab.c @@ -0,0 +1,154 @@ +/* + * MACDRV Wintab implementations + * + * Copyright 2022 Elaine Lefler + * + * 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 "macdrv.h" +#include "macdrv_cocoa.h" + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +#include "cocoa_wintab.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wintab32); + +LOGCONTEXTW macdrv_tablet_ctx; +static LOGCONTEXTW macdrv_system_ctx; + +void* macdrv_tablet_window; +static HWND macdrv_tablet_hwnd; + +static size_t registered_hwnd_count = 0; +static size_t registered_hwnd_cap = 0; +static HWND* registered_hwnd = NULL; + +static const BYTE BUTTON_COUNT = 16; + +BOOL CDECL macdrv_LoadTabletInfo(HWND tablet_hwnd) +{ + static const WCHAR tablet_name[] = {'M','a','c','d','r','v',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0}; + static const WCHAR sys_name[] = {'M','a','c','d','r','v',' ','S','y','s','t','e','m',' ','C','o','n','t','e','x','t',0}; + struct macdrv_win_data* tablet_win_data; + + macdrv_tablet_hwnd = tablet_hwnd; + TRACE("%p\n", macdrv_tablet_hwnd); + + tablet_win_data = get_win_data(macdrv_tablet_hwnd); + macdrv_tablet_window = tablet_win_data->cocoa_window; + release_win_data(tablet_win_data); + + /* TODO?: It is possible to query the Wacom driver for real values, but it + * doesn't report all of these fields anyway and adds a lot of complexity. + * The quick'n'dirty solution is to make a fake tablet with the greatest + * possible capabilities. */ + macdrv_tablet_ctx.lcOptions = CXO_SYSTEM; + macdrv_tablet_ctx.lcLocks = CXL_INSIZE | CXL_INASPECT | CXL_MARGIN + | CXL_SENSITIVITY | CXL_SYSOUT; + macdrv_tablet_ctx.lcStatus = CXS_ONTOP; + macdrv_tablet_ctx.lcMsgBase = WT_DEFBASE; + macdrv_tablet_ctx.lcDevice = 0; + macdrv_tablet_ctx.lcPktRate = 0; /* not supported */ + macdrv_tablet_ctx.lcPktData = PK_CONTEXT | PK_STATUS | PK_TIME | PK_CHANGED + | PK_SERIAL_NUMBER | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | PK_Z + | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION; + macdrv_tablet_ctx.lcPktMode = 0; /* all absolute */ + macdrv_tablet_ctx.lcMoveMask = PK_BUTTONS | PK_X | PK_Y | PK_Z + | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION; + macdrv_tablet_ctx.lcBtnDnMask = (1 << BUTTON_COUNT) - 1; + macdrv_tablet_ctx.lcBtnUpMask = (1 << BUTTON_COUNT) - 1; + + macdrv_tablet_ctx.lcInOrgX = 0; + macdrv_tablet_ctx.lcInOrgY = 0; + /* NSEvent reports floating point coordinates. The actual precision is not + * known, so we convert them to really big values. */ + macdrv_tablet_ctx.lcInExtX = TABLET_WIDTH; + macdrv_tablet_ctx.lcInExtY = TABLET_HEIGHT; + /* These values are correct for Intuos tablets. Wacom's Mac driver doesn't + * reveal them. */ + macdrv_tablet_ctx.lcInOrgZ = -1023; + macdrv_tablet_ctx.lcInExtZ = 2047; + + macdrv_tablet_ctx.lcOutOrgZ = macdrv_tablet_ctx.lcInOrgZ; + macdrv_tablet_ctx.lcOutExtZ = macdrv_tablet_ctx.lcInExtZ; + macdrv_tablet_ctx.lcSensX = 65536; + macdrv_tablet_ctx.lcSensY = 65536; + macdrv_tablet_ctx.lcSensZ = 65536; + + macdrv_tablet_ctx.lcSysMode = 0; /* absolute */ + macdrv_tablet_ctx.lcSysOrgX = GetSystemMetrics(SM_XVIRTUALSCREEN); + macdrv_tablet_ctx.lcSysOrgY = GetSystemMetrics(SM_YVIRTUALSCREEN); + macdrv_tablet_ctx.lcSysExtX = GetSystemMetrics(SM_CXVIRTUALSCREEN); + macdrv_tablet_ctx.lcSysExtY = GetSystemMetrics(SM_CYVIRTUALSCREEN); + macdrv_tablet_ctx.lcSysSensX = 65536; + macdrv_tablet_ctx.lcSysSensY = 65536; + + /* "device" and "system" context are identical, except that "system" + * translates tablet coords to screen coords */ + macdrv_system_ctx = macdrv_tablet_ctx; + strcpyW(macdrv_tablet_ctx.lcName, tablet_name); + strcpyW(macdrv_system_ctx.lcName, sys_name); + + macdrv_tablet_ctx.lcOutOrgX = macdrv_tablet_ctx.lcInOrgX; + macdrv_tablet_ctx.lcOutOrgY = macdrv_tablet_ctx.lcInOrgY; + macdrv_tablet_ctx.lcOutExtX = macdrv_tablet_ctx.lcInExtX; + macdrv_tablet_ctx.lcOutExtY = macdrv_tablet_ctx.lcInExtY; + + macdrv_system_ctx.lcOutOrgX = macdrv_system_ctx.lcSysOrgX; + macdrv_system_ctx.lcOutOrgY = macdrv_system_ctx.lcSysOrgY; + macdrv_system_ctx.lcOutExtX = macdrv_system_ctx.lcSysExtX; + macdrv_system_ctx.lcOutExtY = macdrv_system_ctx.lcSysExtY; + + return TRUE; +} + +UINT CDECL macdrv_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) +{ + TRACE("(%u, %u, %p)\n", wCategory, nIndex, lpOutput); + FIXME("Unhandled Category %i\n", wCategory); + return 0; +} + +int CDECL macdrv_AttachEventQueueToTablet(HWND hOwner) +{ + /* Tablet events come from a global monitor rather than relying on + * individual views. Maintain a list of HWNDs interested in these events so + * we can deliver to them later. */ + if (registered_hwnd_count >= registered_hwnd_cap) + { + registered_hwnd_cap = registered_hwnd_cap * 2 + 1; + registered_hwnd = realloc(registered_hwnd, registered_hwnd_cap * sizeof(*registered_hwnd)); + } + + registered_hwnd[registered_hwnd_count++] = hOwner; + + if (registered_hwnd_count > 1) + FIXME("Multiple contexts are not correctly supported. All events are delivered to all contexts.\n"); + + return 0; +} + +int CDECL macdrv_GetCurrentPacket(LPPACKET packet) +{ + return 0; +}
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback.
This is the largest of the split patches, but unless "segfaults" or "doesn't compile" is acceptable patch behavior, I can't split it any further.
If it's any help, this file looks very similar to winex11.drv/wintab.c. --- dlls/winemac.drv/cocoa_wintab.h | 17 ++ dlls/winemac.drv/wintab.c | 410 +++++++++++++++++++++++++++++++- 2 files changed, 426 insertions(+), 1 deletion(-)
diff --git a/dlls/winemac.drv/cocoa_wintab.h b/dlls/winemac.drv/cocoa_wintab.h index 0fa20f6752c..1b9867c9d34 100644 --- a/dlls/winemac.drv/cocoa_wintab.h +++ b/dlls/winemac.drv/cocoa_wintab.h @@ -21,12 +21,29 @@ #ifndef __WINE_MACDRV_COCOA_WINTAB_H #define __WINE_MACDRV_COCOA_WINTAB_H
+#include <math.h> + #include "windef.h" #include "wintab.h"
/* Extents that shouldn't cause math problems */ #define TABLET_WIDTH 0x40000000 #define TABLET_HEIGHT 0x40000000 +/* Largest reportable pressure value */ +#define MAX_PRESSURE 0x7fff +/* Wacom's demo app teaches developers to assume 1/10th degree. + * Best stick to that. */ +#define ANGLE_SCALE 10 +/* Largest reportable angle (360 is included, due to rounding) */ +#define MAX_ANGLE (360 * ANGLE_SCALE) + +#define MAKE_ANGLE_DEG(degrees) ((degrees) * ANGLE_SCALE) +#define MAKE_ANGLE_RAD(radians) ((radians) * MAKE_ANGLE_DEG(180) / M_PI) + +/* Cursor indices */ +#define MACDRV_CURSOR_PEN 0 +#define MACDRV_CURSOR_ERASER 1 +#define MACDRV_CURSOR_CURSOR 2
/* Shared device context */ extern LOGCONTEXTW macdrv_tablet_ctx DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/wintab.c b/dlls/winemac.drv/wintab.c index fffae85f735..bd6d6b783e0 100644 --- a/dlls/winemac.drv/wintab.c +++ b/dlls/winemac.drv/wintab.c @@ -43,6 +43,29 @@ static size_t registered_hwnd_count = 0; static size_t registered_hwnd_cap = 0; static HWND* registered_hwnd = NULL;
+static const WCHAR CURSOR_NAME_PEN[] = {'P','r','e','s','s','u','r','e',' ','S','t','y','l','u','s',0}; +static const WCHAR CURSOR_NAME_ERASER[] = {'E','r','a','s','e','r',0}; +static const WCHAR CURSOR_NAME_CURSOR[] = {'P','u','c','k',0}; + +static const UINT CURSOR_COUNT = 3; +static const WCHAR* const CURSOR_NAMES[CURSOR_COUNT] = { + CURSOR_NAME_PEN, + CURSOR_NAME_ERASER, + CURSOR_NAME_CURSOR +}; + +static const UINT CURSOR_TYPES[CURSOR_COUNT] = { + CSR_TYPE_PEN, + CSR_TYPE_ERASER, + CSR_TYPE_MOUSE_2D +}; + +static const UINT CURSOR_CAPABILITIES[CURSOR_COUNT] = { + CRC_MULTIMODE | CRC_AGGREGATE, + CRC_MULTIMODE | CRC_AGGREGATE | CRC_INVERT, + CRC_AGGREGATE +}; + static const BYTE BUTTON_COUNT = 16;
BOOL CDECL macdrv_LoadTabletInfo(HWND tablet_hwnd) @@ -125,7 +148,392 @@ BOOL CDECL macdrv_LoadTabletInfo(HWND tablet_hwnd) UINT CDECL macdrv_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) { TRACE("(%u, %u, %p)\n", wCategory, nIndex, lpOutput); - FIXME("Unhandled Category %i\n", wCategory); + + if (IS_WTI_EXTENSIONS_TYPE(wCategory)) + { + FIXME("WTI_EXTENSIONS unimplemented"); + return 0; + } + else if (IS_WTI_CURSORS_TYPE(wCategory)) + { + INT cursor_idx = wCategory - WTI_CURSORS; + if (cursor_idx < 0) + cursor_idx += CURSOR_COUNT; + if (cursor_idx < 0 || cursor_idx >= CURSOR_COUNT) + return 0; + switch (nIndex) + { + case CSR_NAME: + return TABLET_CopyData(lpOutput, CURSOR_NAMES[cursor_idx], (strlenW(CURSOR_NAMES[cursor_idx]) + 1) * sizeof(WCHAR)); + case CSR_ACTIVE: + { + BOOL active = 1; + return TABLET_CopyData(lpOutput, &active, sizeof(active)); + } + case CSR_PKTDATA: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktData, sizeof(macdrv_tablet_ctx.lcPktData)); + case CSR_BUTTONS: + case CSR_BUTTONBITS: + return TABLET_CopyData(lpOutput, &BUTTON_COUNT, sizeof(BUTTON_COUNT)); + case CSR_BTNNAMES: + { + static const char* const fmt = "button %d"; + static char buffer[10]; + int out_size = 0; + PWCHAR out_char = lpOutput; + int button; + + /* Each button name is \0-terminated, with an extra \0 at the + * end. */ + for (button = 0; button < BUTTON_COUNT; button++) + { + int name_len; + + snprintf(buffer, sizeof(buffer), fmt, button); + name_len = strlen(buffer); + + out_size += name_len + 1; + if (out_char != NULL) + { + int c; + for(c = 0; c <= name_len; c++) + *(out_char++) = buffer[c]; + } + } + if (out_char != NULL) + *out_char = 0; + return (out_size + 1) * sizeof(WCHAR); + } + case CSR_BUTTONMAP: + case CSR_SYSBTNMAP: + { + PBYTE out_byte = lpOutput; + int b; + + if (out_byte != NULL) + { + /* Always use 1:1 mapping */ + for (b = 0; b < BUTTON_COUNT; b++) + out_byte[b] = b; + } + return BUTTON_COUNT * sizeof(BYTE); + } + case CSR_NPBUTTON: + case CSR_TPBUTTON: + { + BYTE button = 0; + return TABLET_CopyData(lpOutput, &button, sizeof(button)); + } + case CSR_NPBTNMARKS: + case CSR_TPBTNMARKS: + { + static const UINT marks[] = {0, 1}; + return TABLET_CopyData(lpOutput, &marks, sizeof(marks)); + } + case CSR_NPRESPONSE: + case CSR_TPRESPONSE: + { + static const int POINT_COUNT = 256; + PUINT out_uint = lpOutput; + int p; + + if (out_uint != NULL) + { + /* Linear response */ + for (p = 0; p < POINT_COUNT; p++) + out_uint[p] = MAX_PRESSURE * p / POINT_COUNT; + } + return POINT_COUNT * sizeof(UINT); + } + case CSR_PHYSID: + { + DWORD physid = 0xdeadbeef; + return TABLET_CopyData(lpOutput, &physid, sizeof(physid)); + } + case CSR_MODE: + { + UINT mode = (UINT)cursor_idx; + if (!(CURSOR_CAPABILITIES[cursor_idx] & CRC_MULTIMODE)) + return 0; + return TABLET_CopyData(lpOutput, &mode, sizeof(mode)); + } + case CSR_MINPKTDATA: + { + /* Should be safe to assume all tablets support these */ + UINT pktdata = PK_CONTEXT | PK_STATUS | PK_TIME | PK_CHANGED + | PK_SERIAL_NUMBER | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y + | PK_NORMAL_PRESSURE; + if (!(CURSOR_CAPABILITIES[cursor_idx] & CRC_AGGREGATE)) + return 0; + return TABLET_CopyData(lpOutput, &pktdata, sizeof(pktdata)); + } + case CSR_MINBUTTONS: + { + UINT minbuttons = 1; + if (!(CURSOR_CAPABILITIES[cursor_idx] & CRC_AGGREGATE)) + return 0; + return TABLET_CopyData(lpOutput, &minbuttons, sizeof(minbuttons)); + } + case CSR_CAPABILITIES: + return TABLET_CopyData(lpOutput, CURSOR_CAPABILITIES + cursor_idx, sizeof(*CURSOR_CAPABILITIES)); + case CSR_TYPE: + return TABLET_CopyData(lpOutput, CURSOR_TYPES + cursor_idx, sizeof(*CURSOR_TYPES)); + default: + FIXME("WTI_CURSORS+%d unhandled index %i\n", cursor_idx, nIndex); + return 0; + } + } + + /* Non-indexed categories */ + switch (wCategory) + { + case 0: + /* Largest buffer necessary for any category. This is currently + * WTI_CURSORS :: CSR_NPRESPONSE (or CSR_TPRESPONSE). */ + return 256 * sizeof(UINT); + case WTI_INTERFACE: + switch (nIndex) + { + case IFC_WINTABID: + { + static const WCHAR name[] = {'M','a','c','d','r','v',' ','W','i','n','t','a','b',' ','1','.','1',0}; + return TABLET_CopyData(lpOutput, name, sizeof(name)); + } + case IFC_SPECVERSION: + { + static const WORD version = (0x01) | (0x01 << 8); + return TABLET_CopyData(lpOutput, &version, sizeof(version)); + } + case IFC_IMPLVERSION: + { + static const WORD version = (0x00) | (0x01 << 8); + return TABLET_CopyData(lpOutput, &version, sizeof(version)); + } + case IFC_NDEVICES: + { + static const UINT num = 1; + return TABLET_CopyData(lpOutput, &num, sizeof(num)); + } + case IFC_NCURSORS: + { + return TABLET_CopyData(lpOutput, &CURSOR_COUNT, sizeof(CURSOR_COUNT)); + } + case IFC_NCONTEXTS: + { + static const UINT num = 1; + return TABLET_CopyData(lpOutput, &num, sizeof(num)); + } + default: + FIXME("WTI_INTERFACE unhandled index %i\n", nIndex); + return 0; + } + break; + case WTI_DEFCONTEXT: + case WTI_DEFSYSCTX: + case WTI_DDCTXS: + case WTI_DDCTXS - 1: + case WTI_DSCTXS: + case WTI_DSCTXS - 1: + { + BOOL is_sys = (wCategory == WTI_DEFSYSCTX || wCategory == WTI_DSCTXS || wCategory == WTI_DSCTXS - 1); + LPLOGCONTEXTW active_ctx = (is_sys ? &macdrv_system_ctx : &macdrv_tablet_ctx); + switch (nIndex) + { + case 0: + return TABLET_CopyData(lpOutput, active_ctx, sizeof(*active_ctx)); + case CTX_NAME: + return TABLET_CopyData(lpOutput, active_ctx->lcName, (strlenW(active_ctx->lcName) + 1) * sizeof(WCHAR)); + case CTX_OPTIONS: + return TABLET_CopyData(lpOutput, &active_ctx->lcOptions, sizeof(active_ctx->lcOptions)); + case CTX_STATUS: + return TABLET_CopyData(lpOutput, &active_ctx->lcStatus, sizeof(active_ctx->lcStatus)); + case CTX_LOCKS: + return TABLET_CopyData(lpOutput, &active_ctx->lcLocks, sizeof(active_ctx->lcLocks)); + case CTX_MSGBASE: + return TABLET_CopyData(lpOutput, &active_ctx->lcMsgBase, sizeof(active_ctx->lcMsgBase)); + case CTX_DEVICE: + return TABLET_CopyData(lpOutput, &active_ctx->lcDevice, sizeof(active_ctx->lcDevice)); + case CTX_PKTRATE: + return TABLET_CopyData(lpOutput, &active_ctx->lcPktRate, sizeof(active_ctx->lcPktRate)); + case CTX_PKTDATA: + return TABLET_CopyData(lpOutput, &active_ctx->lcPktData, sizeof(active_ctx->lcPktData)); + case CTX_PKTMODE: + return TABLET_CopyData(lpOutput, &active_ctx->lcPktMode, sizeof(active_ctx->lcPktMode)); + case CTX_MOVEMASK: + return TABLET_CopyData(lpOutput, &active_ctx->lcMoveMask, sizeof(active_ctx->lcMoveMask)); + case CTX_BTNDNMASK: + return TABLET_CopyData(lpOutput, &active_ctx->lcBtnDnMask, sizeof(active_ctx->lcBtnDnMask)); + case CTX_BTNUPMASK: + return TABLET_CopyData(lpOutput, &active_ctx->lcBtnUpMask, sizeof(active_ctx->lcBtnUpMask)); + case CTX_INORGX: + return TABLET_CopyData(lpOutput, &active_ctx->lcInOrgX, sizeof(active_ctx->lcInOrgX)); + case CTX_INORGY: + return TABLET_CopyData(lpOutput, &active_ctx->lcInOrgY, sizeof(active_ctx->lcInOrgY)); + case CTX_INORGZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcInOrgZ, sizeof(active_ctx->lcInOrgZ)); + case CTX_INEXTX: + return TABLET_CopyData(lpOutput, &active_ctx->lcInExtX, sizeof(active_ctx->lcInExtX)); + case CTX_INEXTY: + return TABLET_CopyData(lpOutput, &active_ctx->lcInExtY, sizeof(active_ctx->lcInExtY)); + case CTX_INEXTZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcInExtZ, sizeof(active_ctx->lcInExtZ)); + case CTX_OUTORGX: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutOrgX, sizeof(active_ctx->lcOutOrgX)); + case CTX_OUTORGY: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutOrgY, sizeof(active_ctx->lcOutOrgY)); + case CTX_OUTORGZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutOrgZ, sizeof(active_ctx->lcOutOrgZ)); + case CTX_OUTEXTX: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutExtX, sizeof(active_ctx->lcOutExtX)); + case CTX_OUTEXTY: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutExtY, sizeof(active_ctx->lcOutExtY)); + case CTX_OUTEXTZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutExtZ, sizeof(active_ctx->lcOutExtZ)); + case CTX_SENSX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSensX, sizeof(active_ctx->lcSensX)); + case CTX_SENSY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSensY, sizeof(active_ctx->lcSensY)); + case CTX_SENSZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcSensZ, sizeof(active_ctx->lcSensZ)); + case CTX_SYSMODE: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysMode, sizeof(active_ctx->lcSysMode)); + case CTX_SYSORGX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysOrgX, sizeof(active_ctx->lcSysOrgX)); + case CTX_SYSORGY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysOrgY, sizeof(active_ctx->lcSysOrgY)); + case CTX_SYSEXTX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysExtX, sizeof(active_ctx->lcSysExtX)); + case CTX_SYSEXTY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysExtY, sizeof(active_ctx->lcSysExtY)); + case CTX_SYSSENSX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysSensX, sizeof(active_ctx->lcSysSensX)); + case CTX_SYSSENSY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysSensY, sizeof(active_ctx->lcSysSensY)); + default: + FIXME("WTI_DEFSYSCTX unhandled index %i\n", nIndex); + return 0; + } + } + case WTI_DEVICES: + case WTI_DEVICES - 1: + switch (nIndex) + { + case DVC_NAME: + { + static const WCHAR name[] = {'M','a','c','d','r','v',' ','T','a','b','l','e','t',0}; + return TABLET_CopyData(lpOutput, name, sizeof(name)); + } + case DVC_HARDWARE: + { + static const UINT hardware = HWC_HARDPROX; + return TABLET_CopyData(lpOutput, &hardware, sizeof(hardware)); + } + case DVC_NCSRTYPES: + { + static const UINT num = 0; + return TABLET_CopyData(lpOutput, &num, sizeof(num)); + } + case DVC_FIRSTCSR: + { + static const UINT first = 0; + return TABLET_CopyData(lpOutput, &first, sizeof(first)); + } + case DVC_PKTRATE: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktRate, sizeof(macdrv_tablet_ctx.lcPktRate)); + case DVC_PKTDATA: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktData, sizeof(macdrv_tablet_ctx.lcPktData)); + case DVC_PKTMODE: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktMode, sizeof(macdrv_tablet_ctx.lcPktMode)); + case DVC_CSRDATA: + { + static const WTPKT data = 0; + return TABLET_CopyData(lpOutput, &data, sizeof(data)); + } + case DVC_XMARGIN: + case DVC_YMARGIN: + case DVC_ZMARGIN: + { + static const INT margin = 0; + return TABLET_CopyData(lpOutput, &margin, sizeof(margin)); + } + case DVC_X: + case DVC_Y: + case DVC_Z: + { + UINT org = (nIndex == DVC_X ? macdrv_tablet_ctx.lcInOrgX : nIndex == DVC_Y ? macdrv_tablet_ctx.lcInOrgY : macdrv_tablet_ctx.lcInOrgZ); + UINT ext = (nIndex == DVC_X ? macdrv_tablet_ctx.lcInExtX : nIndex == DVC_Y ? macdrv_tablet_ctx.lcInExtY : macdrv_tablet_ctx.lcInExtZ); + AXIS ax = { + .axMin = org, + .axMax = org + ext - 1, + .axUnits = TU_NONE, + .axResolution = 1 + }; + return TABLET_CopyData(lpOutput, &ax, sizeof(ax)); + } + case DVC_NPRESSURE: + { + static const AXIS ax = { + .axMin = 0, + .axMax = MAX_PRESSURE, + .axUnits = TU_NONE, + .axResolution = 1 + }; + return TABLET_CopyData(lpOutput, &ax, sizeof(ax)); + } + case DVC_TPRESSURE: + { + static const AXIS ax = { + .axMin = -MAX_PRESSURE, + .axMax = MAX_PRESSURE, + .axUnits = TU_NONE, + .axResolution = 1 + }; + return TABLET_CopyData(lpOutput, &ax, sizeof(ax)); + } + case DVC_ORIENTATION: + { + static const AXIS axes[] = { + /*.orAzimuth = */ { + .axMin = 0, + .axMax = MAX_ANGLE, + .axUnits = TU_CIRCLE, + .axResolution = CASTFIX32(MAX_ANGLE) + }, + /*.orAltitude = */ { + .axMin = -MAKE_ANGLE_DEG(90), + .axMax = MAKE_ANGLE_DEG(90), + .axUnits = TU_CIRCLE, + .axResolution = CASTFIX32(MAX_ANGLE) + }, + /*.orTwist = */ { + .axMin = 0, + .axMax = MAX_ANGLE, + .axUnits = TU_CIRCLE, + .axResolution = CASTFIX32(MAX_ANGLE) + } + }; + return TABLET_CopyData(lpOutput, &axes, sizeof(axes)); + } + case DVC_ROTATION: + /* Unsupported */ + return 0; + case DVC_PNPID: + { + static const WCHAR pnpId[] = {'n','o','n','-','p','l','u','g','-','n','-','p','l','a','y',0}; + return TABLET_CopyData(lpOutput, pnpId, sizeof(pnpId)); + } + default: + FIXME("WTI_DEVICES unhandled index %i\n", nIndex); + return 0; + } + break; + default: + if (IS_WTI_DEVICES_TYPE(wCategory) || IS_WTI_DDCTXS_TYPE(wCategory) + || IS_WTI_DSCTXS_TYPE(wCategory)) + /* User error, there's only one device */ + return 0; + FIXME("Unhandled Category %i\n", wCategory); + } return 0; }
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback.
I'm afraid this is also a fairly large patch, but there's no way to reduce it without leaving dead code. --- dlls/winemac.drv/Makefile.in | 3 +- dlls/winemac.drv/cocoa_wintab.h | 13 ++ dlls/winemac.drv/cocoa_wintab.m | 219 ++++++++++++++++++++++++++++++++ dlls/winemac.drv/event.c | 3 + dlls/winemac.drv/macdrv.h | 1 + dlls/winemac.drv/macdrv_cocoa.h | 11 ++ dlls/winemac.drv/wintab.c | 74 ++++++++++- 7 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 dlls/winemac.drv/cocoa_wintab.m
diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in index 47b7c68feb3..5fc8f4152fe 100644 --- a/dlls/winemac.drv/Makefile.in +++ b/dlls/winemac.drv/Makefile.in @@ -33,6 +33,7 @@ OBJC_SRCS = \ cocoa_main.m \ cocoa_opengl.m \ cocoa_status_item.m \ - cocoa_window.m + cocoa_window.m \ + cocoa_wintab.m
RC_SRCS = winemac.rc diff --git a/dlls/winemac.drv/cocoa_wintab.h b/dlls/winemac.drv/cocoa_wintab.h index 1b9867c9d34..0b85bd2ad0d 100644 --- a/dlls/winemac.drv/cocoa_wintab.h +++ b/dlls/winemac.drv/cocoa_wintab.h @@ -23,6 +23,13 @@
#include <math.h>
+#ifdef __OBJC__ +/* Necessary hack because this header must be included on both the Wine side + * and from Objective-C */ +typedef BOOL OBJC_BOOL; +#define BOOL WIN_BOOL +#endif + #include "windef.h" #include "wintab.h"
@@ -48,4 +55,10 @@ /* Shared device context */ extern LOGCONTEXTW macdrv_tablet_ctx DECLSPEC_HIDDEN;
+/* Window to which tablet events are delivered */ +extern void* macdrv_tablet_window DECLSPEC_HIDDEN; + +/* Objective-C function to start tablet events */ +void CDECL macdrv_start_tablet_monitor(void) DECLSPEC_HIDDEN; + #endif /* !defined(__WINE_MACDRV_COCOA_WINTAB_H) */ diff --git a/dlls/winemac.drv/cocoa_wintab.m b/dlls/winemac.drv/cocoa_wintab.m new file mode 100644 index 00000000000..da0c2e91df4 --- /dev/null +++ b/dlls/winemac.drv/cocoa_wintab.m @@ -0,0 +1,219 @@ +/* + * MACDRV Cocoa wintab implementations + * + * Copyright 2022 Elaine Lefler + * + * 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 "cocoa_app.h" +#include "cocoa_event.h" +#include "cocoa_window.h" +#include "cocoa_wintab.h" + +static UINT packet_id = 0; +static UINT current_cursor = MACDRV_CURSOR_CURSOR; + +static CFMachPortRef event_tap; + +static const CGEventMask MOUSE_DOWN_EVENTS = + CGEventMaskBit(kCGEventLeftMouseDown) + | CGEventMaskBit(kCGEventRightMouseDown) + | CGEventMaskBit(kCGEventOtherMouseDown); +static const CGEventMask MOUSE_UP_EVENTS = + CGEventMaskBit(kCGEventLeftMouseUp) + | CGEventMaskBit(kCGEventRightMouseUp) + | CGEventMaskBit(kCGEventOtherMouseUp); +static const CGEventMask MOUSE_DRAG_EVENTS = + CGEventMaskBit(kCGEventLeftMouseDragged) + | CGEventMaskBit(kCGEventRightMouseDragged) + | CGEventMaskBit(kCGEventOtherMouseDragged); + +static const CGEventMask MOUSE_EVENTS = + CGEventMaskBit(kCGEventMouseMoved) + | MOUSE_DOWN_EVENTS | MOUSE_UP_EVENTS | MOUSE_DRAG_EVENTS; + +static const CGEventMask TABLET_EVENTS = + CGEventMaskBit(kCGEventTabletPointer) + | CGEventMaskBit(kCGEventTabletProximity); + +static UINT cursor_from_nx(NSPointingDeviceType device_type) +{ + switch (device_type) + { + case NX_TABLET_POINTER_PEN: + return MACDRV_CURSOR_PEN; + case NX_TABLET_POINTER_ERASER: + return MACDRV_CURSOR_ERASER; + default: + /* Squash Unknown into Cursor */ + return MACDRV_CURSOR_CURSOR; + } +} + +static void packet_from_cgevent(PACKET* pkt, CGEventRef event) +{ + static const double ALTI_VECTOR_SCALE = 0.89879404629916700; /* cos(26) */ + static const double IN_VECTOR_ANGLE_SCALE = .073519026192766368; /* (cos(19) / cos(26) - 1) * sqrt(2) */ + + double azimuth, altitude; + double angle_scale, max_length, length; + + CGPoint location = CGEventGetUnflippedLocation(event); + double tilt_x = CGEventGetDoubleValueField(event, kCGTabletEventTiltX); + double tilt_y = CGEventGetDoubleValueField(event, kCGTabletEventTiltY); + uint64_t time_ns = CGEventGetTimestamp(event); + pkt->pkStatus = (current_cursor == MACDRV_CURSOR_ERASER ? TPS_INVERT : 0); + pkt->pkTime = [[WineApplicationController sharedController] ticksForEventTime:time_ns / (double)NSEC_PER_SEC]; + pkt->pkSerialNumber = ++packet_id; + + pkt->pkCursor = current_cursor; + pkt->pkButtons = CGEventGetIntegerValueField(event, kCGTabletEventPointButtons); + + location = cgpoint_win_from_mac(location); + + /* y should be y-1 because of the way "unflipped" location is calculated. + * We don't -1 the extents because macOS doesn't map the tablet that way. */ + pkt->pkX = (location.x - (double)macdrv_tablet_ctx.lcSysOrgX) / macdrv_tablet_ctx.lcSysExtX * TABLET_WIDTH; + pkt->pkY = (location.y - 1 - (double)macdrv_tablet_ctx.lcSysOrgY) / macdrv_tablet_ctx.lcSysExtY * TABLET_HEIGHT; + pkt->pkZ = CGEventGetIntegerValueField(event, kCGTabletEventPointZ); + + pkt->pkNormalPressure = CGEventGetDoubleValueField(event, kCGTabletEventPointPressure) * MAX_PRESSURE; + pkt->pkTangentPressure = CGEventGetDoubleValueField(event, kCGTabletEventTangentialPressure) * MAX_PRESSURE; + + /* Find the angle around the Z axis. Note that 0 is up and angles move + * clockwise. Swapping x and y gives the correct angle. */ + azimuth = atan2(tilt_x, tilt_y); + /* Adjust to 0..360 range */ + if (azimuth < 0.) + azimuth += 2 * M_PI; + + /* With the pen resting on its barrel and oriented horizontally or + * vertically, a real tablet reads an altitude of 26. This corresponds to a + * tilt of 1. Spinning it to a 45 degree angle allows reading a little bit + * lower, down to 19. However, the X/Y tilt appears to report values that + * are out of range for wintab. Cap the vector at a value that smoothly + * transitions between 1 and the maximum length based on the azimuth. */ + angle_scale = fmin(fabs(cos(azimuth)), fabs(sin(azimuth))); + max_length = 1. + IN_VECTOR_ANGLE_SCALE * angle_scale; + + /* Since the pen moves in a circular path we can calculate the altitude as + * the arccosine of the X/Y vector. Multiply it by cos(26) such that a + * vector of length 1 maps to 26 degrees. */ + length = fmin(max_length, sqrt(tilt_x * tilt_x + tilt_y * tilt_y)); + altitude = acos(length * ALTI_VECTOR_SCALE); + + pkt->pkOrientation.orAzimuth = MAKE_ANGLE_RAD(azimuth); + /* Altitude is negative on the eraser */ + pkt->pkOrientation.orAltitude = MAKE_ANGLE_RAD(!(pkt->pkStatus & TPS_INVERT) ? altitude : -altitude); + /* Rotation is the same as twist */ + pkt->pkOrientation.orTwist = MAKE_ANGLE_DEG(CGEventGetDoubleValueField(event, kCGTabletEventRotation)); +} + +static CGEventRef tablet_event_cb(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) +{ + CGEventMask type_mask; + BOOL is_proximity; + + macdrv_event* out_event; + + /* Tap can be disabled for various reasons, make sure it comes back */ + if (type == kCGEventTapDisabledByTimeout + || type == kCGEventTapDisabledByUserInput) + { + CGEventTapEnable(event_tap, YES); + return event; + } + + type_mask = CGEventMaskBit(type); + is_proximity = (type == kCGEventTabletProximity); + + if (!(type_mask & TABLET_EVENTS)) + { + int64_t subtype = CGEventGetIntegerValueField(event, kCGMouseEventSubtype); + if (subtype == kCGEventMouseSubtypeTabletProximity) + is_proximity = YES; + else if (subtype != kCGEventMouseSubtypeTabletPoint) + /* Not a tablet event */ + return event; + } + + /*NSLog(@"%@", [NSEvent eventWithCGEvent:event]);*/ + out_event = macdrv_create_event(TABLET_EVENT, (WineWindow*)macdrv_tablet_window); + + if (is_proximity) + { + /* Cursor type only appears during proximity events */ + current_cursor = cursor_from_nx(CGEventGetIntegerValueField(event, kCGTabletProximityEventPointerType)); + + if (CGEventGetIntegerValueField(event, kCGTabletProximityEventEnterProximity) != 0) + out_event->tablet_event.type = TABLET_EVENT_PROXIMITY_ENTER; + else + out_event->tablet_event.type = TABLET_EVENT_PROXIMITY_LEAVE; + } + else + { + PACKET* event_packet = calloc(1, sizeof(PACKET)); + packet_from_cgevent(event_packet, event); + out_event->tablet_event.type = TABLET_EVENT_POINT; + out_event->tablet_event.packet = event_packet; + } + + [[(WineWindow*)macdrv_tablet_window queue] postEvent:out_event]; + macdrv_release_event(out_event); + return event; +} + +static void* macdrv_tablet_main(void* _) +{ + CFRunLoopSourceRef source; + event_tap = CGEventTapCreate(kCGAnnotatedSessionEventTap, kCGHeadInsertEventTap, + kCGEventTapOptionListenOnly, MOUSE_EVENTS | TABLET_EVENTS, tablet_event_cb, NULL); + + if (!event_tap) + return NULL; + + source = CFMachPortCreateRunLoopSource(NULL, event_tap, 0); + if (!source) + { + CFRelease(event_tap); + return NULL; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); + CFRelease(source); + + CFRunLoopRun(); + + CFRelease(event_tap); + return NULL; +} + +void CDECL macdrv_start_tablet_monitor(void) +{ + /* Install a global monitor for relevant events. This ensures we can deliver + * the full device area and event frequency that the tablet offers. It's + * essential to run the monitor in its own thread, because CoreGraphics + * blocks event handling until it's done. Scheduling on a busy thread would + * cause the mouse to lag. */ + static pthread_t thread; + if (!thread) + { + if (pthread_create(&thread, NULL, macdrv_tablet_main, NULL) == 0) + pthread_detach(thread); + } +} diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index f197af0808e..22caf0cf2a7 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -308,6 +308,9 @@ void macdrv_handle_event(const macdrv_event *event) case WINDOW_RESTORE_REQUESTED: macdrv_window_restore_requested(hwnd, event); break; + case TABLET_EVENT: + macdrv_tablet_event(event); + break; default: TRACE(" ignoring\n"); break; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 4e4524722af..3eecb26a01e 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -232,6 +232,7 @@ extern DWORD CDECL macdrv_MsgWaitForMultipleObjectsEx(DWORD count, const HANDLE extern void macdrv_window_drag_begin(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_window_drag_end(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_reassert_window_position(HWND hwnd) DECLSPEC_HIDDEN; +extern void macdrv_tablet_event(const macdrv_event *event) DECLSPEC_HIDDEN; extern BOOL query_resize_size(HWND hwnd, macdrv_query *query) DECLSPEC_HIDDEN; extern BOOL query_resize_start(HWND hwnd) DECLSPEC_HIDDEN; extern BOOL query_min_max_info(HWND hwnd) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 94f9fbcfa17..c7f87888fdc 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -351,6 +351,7 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, WINDOW_MINIMIZE_REQUESTED, WINDOW_RESIZE_ENDED, WINDOW_RESTORE_REQUESTED, + TABLET_EVENT, NUM_EVENT_TYPES };
@@ -361,6 +362,12 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, QUIT_REASON_SHUTDOWN, };
+enum { + TABLET_EVENT_POINT, + TABLET_EVENT_PROXIMITY_ENTER, + TABLET_EVENT_PROXIMITY_LEAVE, +}; + typedef uint64_t macdrv_event_mask;
typedef struct macdrv_event { @@ -455,6 +462,10 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, int keep_frame; CGRect frame; } window_restore_requested; + struct { + int type; + void *packet; + } tablet_event; }; } macdrv_event;
diff --git a/dlls/winemac.drv/wintab.c b/dlls/winemac.drv/wintab.c index bd6d6b783e0..11979afba59 100644 --- a/dlls/winemac.drv/wintab.c +++ b/dlls/winemac.drv/wintab.c @@ -38,6 +38,8 @@ static LOGCONTEXTW macdrv_system_ctx;
void* macdrv_tablet_window; static HWND macdrv_tablet_hwnd; +static PACKET current_packet; +static int last_event_type = -1;
static size_t registered_hwnd_count = 0; static size_t registered_hwnd_cap = 0; @@ -553,10 +555,80 @@ int CDECL macdrv_AttachEventQueueToTablet(HWND hOwner) if (registered_hwnd_count > 1) FIXME("Multiple contexts are not correctly supported. All events are delivered to all contexts.\n");
+ macdrv_start_tablet_monitor(); return 0; }
+/*********************************************************************** + * macdrv_tablet_event + * + * Handler for TABLET_EVENT events. + */ +void macdrv_tablet_event(const macdrv_event* event) +{ + int i; + PACKET* old_pkt = ¤t_packet; + PACKET* new_pkt = event->tablet_event.packet; + int event_type = event->tablet_event.type; + BOOL is_proximity = (event_type != TABLET_EVENT_POINT); + + if (is_proximity) + { + /* Wacom's documentation very confusingly states: + * > The high-order word is non-zero when the cursor is leaving or + * > entering hardware proximity. + * What it actually means is that the high-order word is 1 when entering + * proximity or 0 when leaving proximity. + * + * The low and high order words are always the same. The only way to + * enter/leave context proximity without entering/leaving device + * proximity is to have multiple contexts. Macdrv has no awareness of + * contexts so this would have to be handled by wintab.dll. */ + BOOL is_enter = (event_type == TABLET_EVENT_PROXIMITY_ENTER); + LPARAM l_param = MAKELPARAM(is_enter, is_enter); + + /* We can get duplicate events due to NSEventTypeMouseMoved + + * NSEventTypeTabletProximity both being delivered. Squash them here. */ + if (last_event_type == event_type) + return; + + last_event_type = event_type; + + for (i = 0; i < registered_hwnd_count; i++) + { + HWND hwnd = registered_hwnd[i]; + SendMessageW(macdrv_tablet_hwnd, WT_PROXIMITY, (WPARAM)hwnd, l_param); + } + } + else + { + last_event_type = TABLET_EVENT_POINT; + + /* Calculate which values changed */ + new_pkt->pkChanged = ((new_pkt->pkStatus != old_pkt->pkStatus) * PK_STATUS) + | ((new_pkt->pkTime != old_pkt->pkTime) * PK_TIME) + | PK_SERIAL_NUMBER + | ((new_pkt->pkButtons != old_pkt->pkButtons) * PK_BUTTONS) + | ((new_pkt->pkX != old_pkt->pkX) * PK_X) + | ((new_pkt->pkY != old_pkt->pkY) * PK_Y) + | ((new_pkt->pkZ != old_pkt->pkZ) * PK_Z) + | ((new_pkt->pkNormalPressure != old_pkt->pkNormalPressure) * PK_NORMAL_PRESSURE) + | ((new_pkt->pkTangentPressure != old_pkt->pkTangentPressure) * PK_TANGENT_PRESSURE) + | ((memcmp(&new_pkt->pkOrientation, &old_pkt->pkOrientation, sizeof(new_pkt->pkOrientation)) != 0) * PK_ORIENTATION); + + *old_pkt = *new_pkt; + free(new_pkt); + + for (i = 0; i < registered_hwnd_count; i++) + { + HWND hwnd = registered_hwnd[i]; + SendMessageW(macdrv_tablet_hwnd, WT_PACKET, (WPARAM)current_packet.pkSerialNumber, (LPARAM)hwnd); + } + } +} + int CDECL macdrv_GetCurrentPacket(LPPACKET packet) { - return 0; + *packet = current_packet; + return 1; }
Wine apps no longer accept the first mouse click when the application is inactive. This mirrors the expected behavior of Mac apps and prevents a bug where focus is never received.
Call SetActiveWindow(NULL) on deactivate to prevent a bug where focus is never lost.
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Was PATCH 2/3. No changes from v1. --- dlls/winemac.drv/cocoa_app.m | 9 ++++++--- dlls/winemac.drv/window.c | 1 + 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index b5a3059382e..8c525333e8d 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1524,15 +1524,18 @@ - (void) handleMouseButton:(NSEvent*)theEvent { if (mouseCaptureWindow) process = TRUE; - else + /* Don't deliver mouse-down to an application that isn't active. + * This mirrors macOS's behavior and delivering the mouse event + * before activate can make the window fail to receive focus. */ + else if ([[NSApplication sharedApplication] isActive]) { - // Test if the click was in the window's content area. + /* Test if the click was in the window's content area. */ NSPoint nspoint = [self flippedMouseLocation:NSPointFromCGPoint(pt)]; NSRect contentRect = [window contentRectForFrameRect:[window frame]]; process = NSMouseInRect(nspoint, contentRect, NO); if (process && [window styleMask] & NSWindowStyleMaskResizable) { - // Ignore clicks in the grow box (resize widget). + /* Ignore clicks in the grow box (resize widget). */ HIPoint origin = { 0, 0 }; HIThemeGrowBoxDrawInfo info = { 0 }; HIRect bounds; diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 4f3dbc08311..9177f493a5f 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -2415,6 +2415,7 @@ void macdrv_app_deactivated(void) TRACE("setting fg to desktop\n"); SetForegroundWindow(GetDesktopWindow()); } + SetActiveWindow(NULL); }
Allows layered window to handle invisible-pixel clicks properly.
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Was PATCH 3/3. Splitting into smaller patches as per feedback. --- dlls/winemac.drv/cocoa_window.h | 1 + dlls/winemac.drv/cocoa_window.m | 111 ++++++++++++++++++++++++-------- 2 files changed, 84 insertions(+), 28 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index a83f2aa803b..b1f7e595ec9 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -53,6 +53,7 @@ @interface WineWindow : NSPanel <NSWindowDelegate> NSRect wineFrame; NSRect roundedWineFrame;
+ NSData* shapeData; BOOL shapeChangedSinceLastDraw;
BOOL colorKeyed; diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index bfa7e2fe8cc..1b66c97b19a 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -404,6 +404,7 @@ @interface WineWindow () @property (nonatomic) void* surface; @property (nonatomic) pthread_mutex_t* surface_mutex;
+@property (retain, nonatomic) NSData* shapeData; @property (nonatomic) BOOL shapeChangedSinceLastDraw; @property (readonly, nonatomic) BOOL needsTransparency;
@@ -416,8 +417,6 @@ @interface WineWindow ()
@property (readonly, copy, nonatomic) NSArray* childWineWindows;
- - (void) setShape:(CGPathRef)newShape; - - (void) updateForGLSubviews;
- (BOOL) becameEligibleParentOrChild; @@ -491,6 +490,42 @@ - (BOOL) isFlipped return YES; }
+ - (NSView*) hitTest:(NSPoint)point + { + WineWindow* window = (WineWindow*)[self window]; + NSPoint localPoint; + CGPoint cgPoint; + + if (window.contentView != self || !window.shapeData) + return [super hitTest:point]; + + localPoint = [self convertPoint:point fromView:self.superview]; + cgPoint = cgpoint_win_from_mac(NSPointToCGPoint(localPoint)); + + if (window.shapeData) + { + NSPoint nsPoint = NSPointFromCGPoint(cgPoint); + const CGRect* rects = (const CGRect*)window.shapeData.bytes; + NSUInteger count = window.shapeData.length / sizeof(*rects); + BOOL inShape = NO; + NSUInteger i; + + for (i = 0; i < count; i++) + { + if (NSMouseInRect(nsPoint, NSRectFromCGRect(rects[i]), NO)) + { + inShape = YES; + break; + } + } + + if (!inShape) + return nil; + } + + return [super hitTest:point]; + } + - (BOOL) wantsUpdateLayer { return YES /*!_everHadGLContext*/; @@ -958,7 +993,7 @@ @implementation WineWindow @synthesize disabled, noForeground, preventsAppActivation, floating, fullscreen, fakingClose, closing, latentParentWindow, hwnd, queue; @synthesize drawnSinceShown; @synthesize surface, surface_mutex; - @synthesize shapeChangedSinceLastDraw; + @synthesize shapeData, shapeChangedSinceLastDraw; @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue; @synthesize usePerPixelAlpha; @synthesize imeData, commandDone; @@ -1062,6 +1097,7 @@ - (void) dealloc [queue release]; [latentChildWindows release]; [latentParentWindow release]; + [shapeData release]; [super dealloc]; }
@@ -2032,23 +2068,47 @@ - (void) checkTransparency } }
- - (void) setShape:(CGPathRef)newShape + - (void) setShapeData:(NSData*)newShapeData { - CALayer* layer = [[self contentView] layer]; - CAShapeLayer* mask = (CAShapeLayer*)layer.mask; - if (CGPathEqualToPath(newShape, mask.path)) return; + if (shapeData == newShapeData) + return; + + if ([newShapeData length] == 0) + newShapeData = nil; + + if (shapeData) + { + CGRect boundingBox = CGPathGetBoundingBox([(CAShapeLayer*)self.contentView.layer.mask path]); + [shapeData release]; + [self.contentView setNeedsDisplayInRect:NSRectFromCGRect(boundingBox)]; + } + + if (newShapeData) + { + const CGRect* rects = (const CGRect*)newShapeData.bytes; + NSUInteger count = newShapeData.length / sizeof(*rects); + NSUInteger i; + + CGMutablePathRef path = CGPathCreateMutable(); + CAShapeLayer* maskLayer; + + for (i = 0; i < count; i++) + CGPathAddRect(path, nil, cgrect_mac_from_win(rects[i])); + + maskLayer = [CAShapeLayer layer]; + maskLayer.path = path; + self.contentView.layer.mask = maskLayer;
- if (newShape && !layer.mask) - layer.mask = mask = [CAShapeLayer layer]; - else if (!newShape) - layer.mask = mask = nil; + [self.contentView setNeedsDisplayInRect:NSRectFromCGRect(CGPathGetBoundingBox(path))];
- if (mask.path) - [[self contentView] setNeedsDisplayInRect:NSRectFromCGRect(CGPathGetBoundingBox(mask.path))]; - if (newShape) - [[self contentView] setNeedsDisplayInRect:NSRectFromCGRect(CGPathGetBoundingBox(newShape))]; + CFRelease(path); + } + else + { + self.contentView.layer.mask = nil; + }
- mask.path = newShape; + shapeData = [newShapeData retain]; self.shapeChangedSinceLastDraw = TRUE;
[self checkTransparency]; @@ -2250,8 +2310,7 @@ - (void) checkWineDisplayLink
- (BOOL) isEmptyShaped { - CAShapeLayer* mask = (CAShapeLayer*)[[self contentView] layer].mask; - return ([mask isEmptyShaped]); + return (self.shapeData.length == sizeof(CGRectZero) && !memcmp(self.shapeData.bytes, &CGRectZero, sizeof(CGRectZero))); }
- (BOOL) canProvideSnapshot @@ -3471,19 +3530,15 @@ void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count) OnMainThread(^{ if (!rects || !count) { - [window setShape:NULL]; - [window checkEmptyShaped]; + window.shapeData = nil; } else { - CGMutablePathRef path; - unsigned int i; - - path = CGPathCreateMutable(); - for (i = 0; i < count; i++) - CGPathAddRect(path, NULL, cgrect_mac_from_win(rects[i])); - [window setShape:path]; - CGPathRelease(path); + size_t length = sizeof(*rects) * count; + if (window.shapeData.length != length || memcmp(window.shapeData.bytes, rects, length)) + { + window.shapeData = [NSData dataWithBytes:rects length:length]; + } } });
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Was PATCH 3/3. Splitting into smaller patches as per feedback. --- dlls/winemac.drv/cocoa_window.h | 2 +- dlls/winemac.drv/cocoa_window.m | 8 +- dlls/winemac.drv/macdrv_cocoa.h | 8 +- dlls/winemac.drv/surface.c | 425 ++++++++++++++++++++++++++++---- 4 files changed, 381 insertions(+), 62 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index b1f7e595ec9..596e3c52b3e 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -57,7 +57,7 @@ @interface WineWindow : NSPanel <NSWindowDelegate> BOOL shapeChangedSinceLastDraw;
BOOL colorKeyed; - CGFloat colorKeyRed, colorKeyGreen, colorKeyBlue; + uint8_t colorKeyRed, colorKeyGreen, colorKeyBlue;
BOOL usePerPixelAlpha;
diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 1b66c97b19a..656a5ba2283 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -409,7 +409,7 @@ @interface WineWindow () @property (readonly, nonatomic) BOOL needsTransparency;
@property (nonatomic) BOOL colorKeyed; -@property (nonatomic) CGFloat colorKeyRed, colorKeyGreen, colorKeyBlue; +@property (nonatomic) uint8_t colorKeyRed, colorKeyGreen, colorKeyBlue; @property (nonatomic) BOOL usePerPixelAlpha;
@property (assign, nonatomic) void* imeData; @@ -552,7 +552,7 @@ - (void) updateLayer imageRect.origin.y *= layer.contentsScale; imageRect.size.width *= layer.contentsScale; imageRect.size.height *= layer.contentsScale; - image = create_surface_image(window.surface, &imageRect, FALSE, window.colorKeyed, + image = create_surface_image(window.surface, &imageRect, window.colorKeyed, window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue); } pthread_mutex_unlock(window.surface_mutex); @@ -3561,8 +3561,8 @@ void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha) /*********************************************************************** * macdrv_set_window_color_key */ -void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat keyGreen, - CGFloat keyBlue) +void macdrv_set_window_color_key(macdrv_window w, uint8_t keyRed, uint8_t keyGreen, + uint8_t keyBlue) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; WineWindow* window = (WineWindow*)w; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index c7f87888fdc..b0eb86133c4 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -581,14 +581,14 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame) DECLSPEC_HIDDEN; extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) DECLSPEC_HIDDEN; extern void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) DECLSPEC_HIDDEN; -extern CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data, int color_keyed, - CGFloat key_red, CGFloat key_green, CGFloat key_blue) DECLSPEC_HIDDEN; +extern CGImageRef create_surface_image(void *window_surface, CGRect *dirty_area, int color_keyed, + uint8_t key_red, uint8_t key_green, uint8_t key_blue) DECLSPEC_HIDDEN; extern int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) DECLSPEC_HIDDEN; extern void macdrv_window_needs_display(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN; extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count) DECLSPEC_HIDDEN; extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha) DECLSPEC_HIDDEN; -extern void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat keyGreen, - CGFloat keyBlue) DECLSPEC_HIDDEN; +extern void macdrv_set_window_color_key(macdrv_window w, uint8_t keyRed, uint8_t keyGreen, + uint8_t keyBlue) DECLSPEC_HIDDEN; extern void macdrv_clear_window_color_key(macdrv_window w) DECLSPEC_HIDDEN; extern void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha) DECLSPEC_HIDDEN; extern void macdrv_give_cocoa_window_focus(macdrv_window w, int activate) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index 6b0abb10780..eed31229473 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -65,6 +65,7 @@ struct macdrv_window_surface HRGN drawn; BOOL use_alpha; RGNDATA *blit_data; + struct shadow_surface *shadow; BYTE *bits; pthread_mutex_t mutex; BITMAPINFO info; /* variable size, must be last */ @@ -72,6 +73,250 @@ struct macdrv_window_surface
static struct macdrv_window_surface *get_mac_surface(struct window_surface *surface);
+/* Shadow surfaces provide a secondary bitmap to enable multithreaded drawing + * without locking the main surface for an extended period of time. + * + * A shadow may contain one or more bitmaps, allocated on demand. Bitmaps are + * kept in a linked list, re-using existing memory whenever possible. This is + * important because paging in large regions of memory can have a latency of + * >20ms, which is not acceptable for drawing. + * + * Unlike macdrv_window_surface, shadow data can be allocated or deallocated + * from a non-Wine thread, so it requires an independent reference counter and + * must not use Windows functions. */ +struct shadow_surface +{ + pthread_mutex_t mutex; + int refcount; + int bitmap_length; /* size of shadow_bitmap in bytes */ + struct shadow_bitmap *bitmaps; /* linked list or NULL */ +}; + +struct shadow_bitmap +{ + union + { + struct + { + struct shadow_surface *parent; + struct shadow_bitmap *next; + CFAllocatorRef cfdata_deallocator; + }; + BYTE pad[32]; /* should be a multiple of 16 */ + }; + BYTE bits[0]; /* variable length */ +}; + +/* Number of shadow bitmaps to keep. Rasterization is asynchronous, so more than + * one bitmap may be alive at any given time. Usually 2 is sufficient. This is + * a failsafe to ensure the list can't grow indefinitely. */ +#define SHADOW_BITMAP_MAX 3 + +static struct shadow_bitmap *shadow_bitmap_free(struct shadow_bitmap *bitmap, + int bitmap_length); +static void shadow_cfdata_dealloc(void *ptr, void *info); + +/*********************************************************************** + * shadow_surface_create + * + * Creates a new shadow surface. Its refcount is initially set to 1. + * Returns NULL on failure. + */ +static struct shadow_surface *shadow_surface_create(struct macdrv_window_surface* parent) +{ + /* Note: actual bitmap length is rounded up to the nearest pagesize */ + int bitmap_length = sizeof(struct shadow_bitmap) + + parent->info.bmiHeader.biSizeImage; + + /* Although this function can only be called from a Windows thread, the + * deallocator can be called from a macOS thread, so we must use calloc + * instead of HeapAlloc. */ + struct shadow_surface *shadow = calloc(1, sizeof(struct shadow_surface)); + if (!shadow) + return NULL; + + if (pthread_mutex_init(&shadow->mutex, NULL) != 0) + { + free(shadow); + return NULL; + } + + shadow->refcount = 1; + shadow->bitmap_length = bitmap_length; + return shadow; +} + +/*********************************************************************** + * shadow_surface_release + * + * Decrements shadow surface's refcount. If it becomes zero, the shadow + * is freed along with all of its bitmaps. + * + * shadow->mutex must be held before calling this function. The mutex + * will be released on exit and you should not attempt to access the + * surface again. + * + * IMPORTANT: This function is called from non-Wine threads, so it + * must not use Win32 or Wine functions, including debug + * logging. + */ +static void shadow_surface_release(struct shadow_surface *shadow) +{ + int bitmap_length = shadow->bitmap_length; + int refcount = --shadow->refcount; + struct shadow_bitmap *bitmap = shadow->bitmaps; + + pthread_mutex_unlock(&shadow->mutex); + + if (refcount != 0) + return; + + pthread_mutex_destroy(&shadow->mutex); + free(shadow); + while (bitmap) + bitmap = shadow_bitmap_free(bitmap, bitmap_length); +} + +/*********************************************************************** + * shadow_bitmap_take + * + * Obtains a shadow bitmap from the given shadow surface. Returns the + * bitmap on success or NULL on failure. + * + * On success, shadow->refcount has been incremented. The call must be + * balanced with a call to shadow_bitmap_return, usually accomplished by + * passing bitmap->cfdata_deallocator to CFDataCreateWithBytesNoCopy as + * bytesDeallocator. + * + * IMPORTANT: This function is called from non-Wine threads, so it + * must not use Win32 or Wine functions, including debug + * logging. + */ +static struct shadow_bitmap *shadow_bitmap_take(struct shadow_surface *shadow) +{ + int bitmap_length; + struct shadow_bitmap *bitmap; + CFAllocatorContext cfa_context = { + .version = 0, .info = NULL, + .retain = NULL, .release = NULL, .copyDescription = NULL, + .allocate = NULL, .reallocate = NULL, + .deallocate = shadow_cfdata_dealloc, .preferredSize = NULL + }; + + pthread_mutex_lock(&shadow->mutex); + shadow->refcount++; + + bitmap_length = shadow->bitmap_length; + bitmap = shadow->bitmaps; + if (bitmap) + { + /* Got an existing bitmap, remove it from the linked list */ + shadow->bitmaps = bitmap->next; + bitmap->next = NULL; + } + + pthread_mutex_unlock(&shadow->mutex); + + if (bitmap) + return bitmap; + + /* Nothing was available, make a new bitmap. Once again we cannot use + * Windows functions. mmap is most appropriate due to its low CPU overhead + * and the fact that bitmaps are usually large. Pass shadow as a hint so the + * bitmap will be allocated in a similar memory region. */ + bitmap = mmap(shadow, bitmap_length, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (bitmap == MAP_FAILED) + goto failed; + + cfa_context.info = bitmap; + bitmap->cfdata_deallocator = CFAllocatorCreate(NULL, &cfa_context); + if (!bitmap->cfdata_deallocator) + goto failed_unmap; + + bitmap->parent = shadow; + return bitmap; + +failed_unmap: + munmap(bitmap, bitmap_length); +failed: + /* Balance refcount++ since shadow_bitmap_return won't be called */ + pthread_mutex_lock(&shadow->mutex); + shadow_surface_release(shadow); + return NULL; +} + +/*********************************************************************** + * shadow_bitmap_return + * + * Returns a shadow bitmap to its linked list and decrements the + * refcount in the corresponding shadow_surface. + * + * IMPORTANT: This function is called from non-Wine threads, so it + * must not use Win32 or Wine functions, including debug + * logging. + */ +static void shadow_bitmap_return(struct shadow_bitmap *bitmap) +{ + struct shadow_surface *shadow = bitmap->parent; + struct shadow_bitmap **tail = &shadow->bitmaps; + int bitmap_length; + int num_bitmaps = 0; + + pthread_mutex_lock(&shadow->mutex); + bitmap_length = shadow->bitmap_length; + + /* Append the bitmap to the end of the list */ + while (*tail) + { + num_bitmaps++; + tail = &(*tail)->next; + } + + /* Refuse to return this bitmap if there are already too many. Free it + * instead. */ + if (num_bitmaps >= SHADOW_BITMAP_MAX) + shadow_bitmap_free(bitmap, bitmap_length); + else + *tail = bitmap; + + shadow_surface_release(shadow); +} + +/*********************************************************************** + * shadow_bitmap_free + * + * Deletes a shadow bitmap. Returns bitmap->next. + * + * IMPORTANT: This function is called from non-Wine threads, so it + * must not use Win32 or Wine functions, including debug + * logging. + */ +static struct shadow_bitmap *shadow_bitmap_free(struct shadow_bitmap *bitmap, + int bitmap_length) +{ + struct shadow_bitmap *next = bitmap->next; + + CFRelease(bitmap->cfdata_deallocator); + munmap(bitmap, bitmap_length); + + return next; +} + +/*********************************************************************** + * shadow_cfdata_dealloc + * + * Wraps shadow_bitmap_return for CFAllocator. + * + * IMPORTANT: This function is called from non-Wine threads, so it + * must not use Win32 or Wine functions, including debug + * logging. + */ +static void shadow_cfdata_dealloc(void *ptr, void *info) +{ + shadow_bitmap_return(info); +} + /*********************************************************************** * update_blit_data */ @@ -207,8 +452,14 @@ static void macdrv_surface_destroy(struct window_surface *window_surface) TRACE("freeing %p bits %p\n", surface, surface->bits); if (surface->region) DeleteObject(surface->region); if (surface->drawn) DeleteObject(surface->drawn); + if (surface->shadow) + { + pthread_mutex_lock(&surface->shadow->mutex); + shadow_surface_release(surface->shadow); + } + if (surface->bits && surface->bits != MAP_FAILED) + munmap(surface->bits, surface->info.bmiHeader.biSizeImage); HeapFree(GetProcessHeap(), 0, surface->blit_data); - HeapFree(GetProcessHeap(), 0, surface->bits); pthread_mutex_destroy(&surface->mutex); HeapFree(GetProcessHeap(), 0, surface); } @@ -293,13 +544,19 @@ struct window_surface *create_surface(macdrv_window window, const RECT *rect, } update_blit_data(surface); surface->use_alpha = use_alpha; - surface->bits = HeapAlloc(GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage); - if (!surface->bits) goto failed; + surface->shadow = shadow_surface_create(surface); + if (!surface->shadow) goto failed; + /* Map bitmap close to the shadow */ + surface->bits = mmap(surface->shadow, surface->info.bmiHeader.biSizeImage, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (surface->bits == MAP_FAILED) goto failed; window_background = macdrv_window_background_color(); memset_pattern4(surface->bits, &window_background, surface->info.bmiHeader.biSizeImage);
- TRACE("created %p for %p %s bits %p-%p\n", surface, window, wine_dbgstr_rect(rect), - surface->bits, surface->bits + surface->info.bmiHeader.biSizeImage); + TRACE("created %p for %p %s bits %p-%p shadow %p\n", + surface, window, wine_dbgstr_rect(rect), + surface->bits, surface->bits + surface->info.bmiHeader.biSizeImage, + surface->shadow);
return &surface->header;
@@ -362,77 +619,139 @@ int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *coun /*********************************************************************** * create_surface_image * - * Caller must hold the surface lock. On input, *rect is the requested - * image rect, relative to the window whole_rect, a.k.a. visible_rect. - * On output, it's been intersected with that part backed by the surface - * and is the actual size of the returned image. copy_data indicates if - * the caller will keep the returned image beyond the point where the - * surface bits can be guaranteed to remain valid and unchanged. If so, - * the bits are copied instead of merely referenced by the image. + * Creates a CGImageRef from the given surface. Returns NULL if there is + * nothing to draw. On input, *dirty_area is the requested image rect, + * relative to the window whole_rect, a.k.a. visible_rect. On output, + * it's been intersected with that part backed by the surface and is the + * actual size of the returned image. * * IMPORTANT: This function is called from non-Wine threads, so it * must not use Win32 or Wine functions, including debug * logging. */ -CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data, int color_keyed, - CGFloat key_red, CGFloat key_green, CGFloat key_blue) +CGImageRef create_surface_image(void *window_surface, CGRect *dirty_area, int color_keyed, + uint8_t key_red, uint8_t key_green, uint8_t key_blue) { - CGImageRef cgimage = NULL; + static CGColorSpaceRef colorspace = NULL; + CGImageAlphaInfo alpha_info = kCGImageAlphaNoneSkipFirst; + CGImageRef cgimage; + CFDataRef data; + CGDataProviderRef provider; + struct macdrv_window_surface *surface = get_mac_surface(window_surface); - int width, height; + struct shadow_bitmap *shadow;
- width = surface->header.rect.right - surface->header.rect.left; - height = surface->header.rect.bottom - surface->header.rect.top; - *rect = CGRectIntersection(cgrect_from_rect(surface->header.rect), *rect); - if (!CGRectIsEmpty(*rect)) - { - CGRect visrect; - CGColorSpaceRef colorspace; - CGDataProviderRef provider; - int bytes_per_row, offset, size; - CGImageAlphaInfo alphaInfo; + int surface_width, bytes_per_row, bitmap_length; + int dirty_width, dirty_height, offset;
- visrect = CGRectOffset(*rect, -surface->header.rect.left, -surface->header.rect.top); + if (!surface) + return NULL;
+ if (!colorspace) colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - bytes_per_row = get_dib_stride(width, 32); - offset = CGRectGetMinX(visrect) * 4 + CGRectGetMinY(visrect) * bytes_per_row; - size = min(CGRectGetHeight(visrect) * bytes_per_row, - surface->info.bmiHeader.biSizeImage - offset);
- if (copy_data) + pthread_mutex_lock(&surface->mutex); + surface_width = surface->header.rect.right - surface->header.rect.left; + bytes_per_row = get_dib_stride(surface_width, 32); + bitmap_length = surface->info.bmiHeader.biSizeImage; + if (surface->use_alpha) + alpha_info = kCGImageAlphaPremultipliedFirst; + + /* Clip to bitmap area */ + *dirty_area = CGRectIntersection(cgrect_from_rect(surface->header.rect), + CGRectIntegral(*dirty_area)); + + dirty_width = CGRectGetWidth(*dirty_area); + dirty_height = CGRectGetHeight(*dirty_area); + + if (dirty_width <= 0 || dirty_height <= 0) + goto failed; + + shadow = shadow_bitmap_take(surface->shadow); + if (!shadow) + goto failed; + + /* Find location from which to read data */ + offset = (CGRectGetMinX(*dirty_area) - surface->header.rect.left) * 4 + + (surface->header.rect.bottom - CGRectGetMaxY(*dirty_area)) + * bytes_per_row; + + if (!color_keyed) + { + /* Copy pixels to shadow buffer. If the width is close or equal to the + * whole bitmap (<= 32 bytes), it's faster to copy one large region. */ + if (dirty_width >= surface_width - 8) { - CFDataRef data = CFDataCreate(NULL, (UInt8*)surface->bits + offset, size); - provider = CGDataProviderCreateWithCFData(data); - CFRelease(data); + /* Align to 16-byte boundaries to get the best memcpy performance */ + int align_offset = offset & ~15; + int align_size = ((offset + (dirty_height - 1) * bytes_per_row + + dirty_width * 4 + 15) & ~15) - align_offset; + memcpy(shadow->bits + align_offset, + surface->bits + align_offset, + align_size); } else - provider = CGDataProviderCreateWithData(NULL, surface->bits + offset, size, NULL); - - alphaInfo = surface->use_alpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; - cgimage = CGImageCreate(CGRectGetWidth(visrect), CGRectGetHeight(visrect), - 8, 32, bytes_per_row, colorspace, - alphaInfo | kCGBitmapByteOrder32Little, - provider, NULL, retina_on, kCGRenderingIntentDefault); - CGDataProviderRelease(provider); - CGColorSpaceRelease(colorspace); + { + /* Copying a smaller width of the bitmap, go line by line */ + int y; + for (y = 0; y < dirty_height; y++) + { + int line_offset = offset + y * bytes_per_row; + int align_offset = line_offset & ~15; + int align_size = ((line_offset + dirty_width * 4 + 15) & ~15) + - align_offset; + memcpy(shadow->bits + align_offset, + surface->bits + align_offset, + align_size); + } + } + } + else + { + /* If using a color key, convert those pixels to transparent. This is + * the best time to do it since we have to copy the data anyway. */ + DWORD key = (key_red << 16) | (key_green << 8) | (key_blue); + int x, y;
- if (color_keyed) + for (y = 0; y < dirty_height; y++) { - CGImageRef maskedImage; - CGFloat components[] = { key_red - 0.5, key_red + 0.5, - key_green - 0.5, key_green + 0.5, - key_blue - 0.5, key_blue + 0.5 }; - maskedImage = CGImageCreateWithMaskingColors(cgimage, components); - if (maskedImage) + for (x = 0; x < dirty_width; x++) { - CGImageRelease(cgimage); - cgimage = maskedImage; + DWORD src = *(DWORD*)(surface->bits + offset + + x * 4 + y * bytes_per_row); + DWORD* dst = (DWORD*)(shadow->bits + offset + + x * 4 + y * bytes_per_row); + if ((src & 0x00FFFFFF) == key) + *dst = 0; + else if (!surface->use_alpha) + /* dst must have alpha channel even if src does not */ + *dst = src | 0xFF000000; + else + *dst = src; } } + + alpha_info = kCGImageAlphaPremultipliedFirst; }
+ /* Safe to unlock surface now */ + pthread_mutex_unlock(&surface->mutex); + + data = CFDataCreateWithBytesNoCopy(NULL, shadow->bits + offset, + bitmap_length - offset, shadow->cfdata_deallocator); + provider = CGDataProviderCreateWithCFData(data); + CFRelease(data); + + cgimage = CGImageCreate(dirty_width, dirty_height, 8, 32, bytes_per_row, + colorspace, alpha_info | kCGBitmapByteOrder32Little, + provider, NULL, FALSE, kCGRenderingIntentDefault); + CFRelease(provider); + return cgimage; + +failed: + pthread_mutex_unlock(&surface->mutex); + return NULL; }
/***********************************************************************
Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Was PATCH 3/3. Splitting into smaller patches as per feedback. --- dlls/winemac.drv/cocoa_app.h | 2 + dlls/winemac.drv/cocoa_app.m | 59 +++++++--- dlls/winemac.drv/cocoa_window.h | 3 +- dlls/winemac.drv/cocoa_window.m | 201 +++++++++++++++----------------- dlls/winemac.drv/macdrv.h | 1 - dlls/winemac.drv/macdrv_cocoa.h | 5 +- dlls/winemac.drv/surface.c | 124 +++++++++----------- dlls/winemac.drv/window.c | 4 +- 8 files changed, 204 insertions(+), 195 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h index 52c91c0621f..b55c55f2995 100644 --- a/dlls/winemac.drv/cocoa_app.h +++ b/dlls/winemac.drv/cocoa_app.h @@ -124,6 +124,8 @@ @interface WineApplicationController : NSObject <NSApplicationDelegate>
id<WineClipCursorHandler> clipCursorHandler;
+ NSMutableArray* wineWindows; + NSImage* applicationIcon;
BOOL beenActive; diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 8c525333e8d..e8b88286d24 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -47,6 +47,25 @@ + (void) setAllowsAutomaticWindowTabbing:(BOOL)allows; #endif
+@interface NSWindow (WineNSPointExtensions) + +/* Reimplementation of -convertPointFromScreen: which isn't available on all + * supported macOS versions */ +- (NSPoint)wineConvertPointFromScreen:(NSPoint)point; + +@end + +@implementation NSWindow (WineNSPointExtensions) + +- (NSPoint)wineConvertPointFromScreen:(NSPoint)point +{ + NSPoint origin = self.frame.origin; + return NSMakePoint(point.x - origin.x, point.y - origin.y); +} + +@end + + /*********************************************************************** * WineLocalizedString * @@ -204,6 +223,7 @@ - (void) dealloc [keyWindows release]; [eventQueues release]; [eventQueuesLock release]; + [wineWindows release]; if (requestsManipQueue) dispatch_release(requestsManipQueue); [requests release]; if (requestSource) @@ -571,7 +591,6 @@ - (WineWindow*) frontWineWindow - (void) adjustWindowLevels:(BOOL)active { NSArray* windowNumbers; - NSMutableArray* wineWindows; NSNumber* windowNumber; NSUInteger nextFloatingIndex = 0; __block NSInteger maxLevel = NSIntegerMin; @@ -582,6 +601,8 @@ - (void) adjustWindowLevels:(BOOL)active
if ([NSApp isHidden]) return;
+ [wineWindows release]; + windowNumbers = [NSWindow windowNumbersWithOptions:0]; wineWindows = [[NSMutableArray alloc] initWithCapacity:[windowNumbers count]];
@@ -652,8 +673,6 @@ - (void) adjustWindowLevels:(BOOL)active
NSEnableScreenUpdates();
- [wineWindows release]; - // The above took care of the visible windows on the current space. That // leaves windows on other spaces, minimized windows, and windows which // are not ordered in. We want to leave windows on other spaces alone @@ -1337,19 +1356,33 @@ - (void) handleMouseMove:(NSEvent*)anEvent targetWindow = (WineWindow*)[anEvent window]; else { - /* Because of the way -[NSWindow setAcceptsMouseMovedEvents:] works, the - event indicates its window is the main window, even if the cursor is - over a different window. Find the actual WineWindow that is under the - cursor and post the event as being for that window. */ + /* Due to our use of NSTrackingArea and the way Cocoa directs mouse + * moves, the window receiving the event is probably not the one + * with the cursor. Find the window that actually has the cursor by + * hit-testing front to back. */ CGPoint cgpoint = CGEventGetLocation([anEvent CGEvent]); NSPoint point = [self flippedMouseLocation:NSPointFromCGPoint(cgpoint)]; - NSInteger windowUnderNumber; + WineWindow* window;
- windowUnderNumber = [NSWindow windowNumberAtPoint:point - belowWindowWithWindowNumber:0]; - targetWindow = (WineWindow*)[NSApp windowWithWindowNumber:windowUnderNumber]; - if (!NSMouseInRect(point, [targetWindow contentRectForFrameRect:[targetWindow frame]], NO)) - targetWindow = nil; + targetWindow = nil; + + for (window in wineWindows) + { + NSPoint windowPoint = [window wineConvertPointFromScreen:point]; + BOOL isHit = ([window.contentView hitTest:windowPoint] != nil); + + /* Windows with transparency must be instructed to ignore + * mouse-downs when the hovered pixel is not visible. The + * window's tracking area still reports events. */ + if (window.needsTransparency) + [window setIgnoresMouseEvents:!isHit && NSMouseInRect(windowPoint, window.contentView.frame, NO)]; + + if (isHit) + { + targetWindow = (WineWindow*)window; + break; + } + } }
if ([targetWindow isKindOfClass:[WineWindow class]]) diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index 596e3c52b3e..675abcc659b 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -45,7 +45,6 @@ @interface WineWindow : NSPanel <NSWindowDelegate> WineEventQueue* queue;
void* surface; - pthread_mutex_t* surface_mutex;
CGDirectDisplayID _lastDisplayID; NSTimeInterval _lastDisplayTime; @@ -95,6 +94,8 @@ @interface WineWindow : NSPanel <NSWindowDelegate> @property (readonly, nonatomic) BOOL noForeground; @property (readonly, nonatomic) BOOL preventsAppActivation; @property (readonly, nonatomic) BOOL floating; +@property (readonly, nonatomic) BOOL needsTransparency; +@property (readonly, nonatomic) BOOL needsLayerTransparency; @property (readonly, getter=isFullscreen, nonatomic) BOOL fullscreen; @property (readonly, getter=isFakingClose, nonatomic) BOOL fakingClose; @property (readonly, nonatomic) NSRect wine_fractionalFrame; diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 656a5ba2283..74a84aab630 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -309,32 +309,6 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi @end
-#ifndef MAC_OS_X_VERSION_10_14 -@protocol NSViewLayerContentScaleDelegate <NSObject> -@optional - - - (BOOL) layer:(CALayer*)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow*)window; - -@end -#endif - - -@interface CAShapeLayer (WineShapeMaskExtensions) - -@property(readonly, nonatomic, getter=isEmptyShaped) BOOL emptyShaped; - -@end - -@implementation CAShapeLayer (WineShapeMaskExtensions) - - - (BOOL) isEmptyShaped - { - return CGRectEqualToRect(CGPathGetBoundingBox(self.path), CGRectZero); - } - -@end - - @interface WineBaseView : NSView @end
@@ -351,10 +325,11 @@ - (id) initWithFrame:(NSRect)frame device:(id<MTLDevice>)device; #endif
-@interface WineContentView : WineBaseView <NSTextInputClient, NSViewLayerContentScaleDelegate> +@interface WineContentView : WineBaseView <NSTextInputClient> { NSMutableArray* glContexts; NSMutableArray* pendingGlContexts; + BOOL _shouldBeHidden; BOOL _everHadGLContext; BOOL _cachedHasGLDescendant; BOOL _cachedHasGLDescendantValid; @@ -363,7 +338,6 @@ @interface WineContentView : WineBaseView <NSTextInputClient, NSViewLayerContent NSMutableAttributedString* markedText; NSRange markedTextSelection;
- BOOL _retinaMode; int backingSize[2];
#ifdef HAVE_METAL_METAL_H @@ -402,11 +376,9 @@ @interface WineWindow () @property (retain, readwrite, nonatomic) WineEventQueue* queue;
@property (nonatomic) void* surface; -@property (nonatomic) pthread_mutex_t* surface_mutex;
@property (retain, nonatomic) NSData* shapeData; @property (nonatomic) BOOL shapeChangedSinceLastDraw; -@property (readonly, nonatomic) BOOL needsTransparency;
@property (nonatomic) BOOL colorKeyed; @property (nonatomic) uint8_t colorKeyRed, colorKeyGreen, colorKeyBlue; @@ -490,13 +462,32 @@ - (BOOL) isFlipped return YES; }
+ - (BOOL) wantsDefaultClipping + { + /* Don't need this, we already limit our drawing to the dirty region */ + return NO; + } + + - (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event + { + /* Returning NSNull ensures the layer will never animate itself */ + return [NSNull null]; + } + + - (BOOL) isOpaque + { + WineWindow* window = (WineWindow*)[self window]; + return window.contentView == self && !window.needsLayerTransparency; + } + - (NSView*) hitTest:(NSPoint)point { WineWindow* window = (WineWindow*)[self window]; NSPoint localPoint; CGPoint cgPoint;
- if (window.contentView != self || !window.shapeData) + if (window.contentView != self + || (!window.shapeData && !window.needsLayerTransparency)) return [super hitTest:point];
localPoint = [self convertPoint:point fromView:self.superview]; @@ -523,72 +514,76 @@ - (NSView*) hitTest:(NSPoint)point return nil; }
- return [super hitTest:point]; - } + if (window.needsLayerTransparency) + { + /* Transparent pixels are not supposed to be clickable, but due to + * contentView.layer.drawsAsynchronously, Cocoa does not enforce it. + * Therefore, we must perform our own per-pixel hit test. */ + if (!surface_hit_test(window.surface, cgPoint, window.colorKeyed, + window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue)) + return nil; + }
- - (BOOL) wantsUpdateLayer - { - return YES /*!_everHadGLContext*/; + return [super hitTest:point]; }
- - (void) updateLayer + - (void) drawRect:(NSRect)rect { WineWindow* window = (WineWindow*)[self window]; - CGImageRef image = NULL; - CGRect imageRect; - CALayer* layer = [self layer]; + CGRect imageRect = cgrect_win_from_mac(NSRectToCGRect(rect)); + CGImageRef image;
- if ([window contentView] != self) - return; + for (WineOpenGLContext* context in pendingGlContexts) + { + if (!clearedGlSurface) + { + context.shouldClearToBlack = TRUE; + clearedGlSurface = TRUE; + } + context.needsUpdate = TRUE; + } + [glContexts addObjectsFromArray:pendingGlContexts]; + [pendingGlContexts removeAllObjects];
- if (window.closing || !window.surface || !window.surface_mutex) + if ([window contentView] != self) return;
- pthread_mutex_lock(window.surface_mutex); - if (get_surface_blit_rects(window.surface, NULL, NULL)) + if ((image = create_surface_image(window.surface, &imageRect, window.colorKeyed, + window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue)) != NULL) { - imageRect = layer.bounds; - imageRect.origin.x *= layer.contentsScale; - imageRect.origin.y *= layer.contentsScale; - imageRect.size.width *= layer.contentsScale; - imageRect.size.height *= layer.contentsScale; - image = create_surface_image(window.surface, &imageRect, window.colorKeyed, - window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue); - } - pthread_mutex_unlock(window.surface_mutex); + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + CGContextSetBlendMode(context, kCGBlendModeCopy); + /* HQ interpolation should be used with retina to prevent artifacts + * on mixed DPI. Not needed for standard DPI. */ + CGContextSetInterpolationQuality(context, retina_on ? kCGInterpolationHigh : kCGInterpolationNone); + + CGContextDrawImage(context, cgrect_mac_from_win(imageRect), image); + CGImageRelease(image);
- if (image) - { - layer.contents = (id)image; - CFRelease(image); [window windowDidDrawContent]; + }
- // If the window may be transparent, then we have to invalidate the - // shadow every time we draw. Also, if this is the first time we've - // drawn since changing from transparent to opaque. - if (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw) - { - window.shapeChangedSinceLastDraw = FALSE; - [window invalidateShadow]; - } + /* If the window may be transparent, then we have to invalidate the + * shadow every time we draw. Also, if this is the first time we've + * drawn since changing from transparent to opaque. */ + if (window.drawnSinceShown && (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw)) + { + window.shapeChangedSinceLastDraw = FALSE; + [window invalidateShadow]; } }
- - (void) viewWillDraw + - (void) setHidden:(BOOL)hidden { - [super viewWillDraw]; - - for (WineOpenGLContext* context in pendingGlContexts) + if (self.window.contentView == self) { - if (!clearedGlSurface) - { - context.shouldClearToBlack = TRUE; - clearedGlSurface = TRUE; - } - context.needsUpdate = TRUE; + [super setHidden:hidden]; + return; } - [glContexts addObjectsFromArray:pendingGlContexts]; - [pendingGlContexts removeAllObjects]; + + /* Client views should always remain hidden, unless we have OpenGL */ + [super setHidden:hidden || !_everHadGLContext]; + _shouldBeHidden = hidden; }
- (void) addGLContext:(WineOpenGLContext*)context @@ -617,7 +612,10 @@ - (void) addGLContext:(WineOpenGLContext*)context
_everHadGLContext = YES; if (!hadContext) + { + [super setHidden:_shouldBeHidden]; [self invalidateHasGLDescendant]; + } [(WineWindow*)[self window] updateForGLSubviews]; }
@@ -721,18 +719,9 @@ - (void) setRetinaMode:(int)mode [self setWantsBestResolutionOpenGLSurface:mode]; [self updateGLContexts];
- _retinaMode = !!mode; - [self layer].contentsScale = mode ? 2.0 : 1.0; - [self layer].minificationFilter = mode ? kCAFilterLinear : kCAFilterNearest; - [self layer].magnificationFilter = mode ? kCAFilterLinear : kCAFilterNearest; [super setRetinaMode:mode]; }
- - (BOOL) layer:(CALayer*)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow*)window - { - return (_retinaMode || newScale == 1.0); - } - - (void) viewDidHide { [super viewDidHide]; @@ -992,7 +981,7 @@ @implementation WineWindow
@synthesize disabled, noForeground, preventsAppActivation, floating, fullscreen, fakingClose, closing, latentParentWindow, hwnd, queue; @synthesize drawnSinceShown; - @synthesize surface, surface_mutex; + @synthesize surface; @synthesize shapeData, shapeChangedSinceLastDraw; @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue; @synthesize usePerPixelAlpha; @@ -1026,7 +1015,6 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w [window disableCursorRects]; [window setShowsResizeIndicator:NO]; [window setHasShadow:wf->shadow]; - [window setAcceptsMouseMovedEvents:YES]; [window setDelegate:window]; [window setBackgroundColor:[NSColor clearColor]]; [window setOpaque:NO]; @@ -1045,12 +1033,10 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w if (!contentView) return nil; [contentView setWantsLayer:YES]; - [contentView layer].minificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [contentView layer].magnificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [contentView layer].contentsScale = retina_on ? 2.0 : 1.0; + [contentView.layer setDrawsAsynchronously:YES]; [contentView setAutoresizesSubviews:NO];
- /* We use tracking areas in addition to setAcceptsMouseMovedEvents:YES + /* We use tracking areas instead of setAcceptsMouseMovedEvents:YES because they give us mouse moves in the background. */ trackingArea = [[[NSTrackingArea alloc] initWithRect:[contentView bounds] options:(NSTrackingMouseMoved | @@ -2044,28 +2030,37 @@ - (void) setDisabled:(BOOL)newValue } }
+ - (BOOL) needsLayerTransparency + { + return self.colorKeyed || self.usePerPixelAlpha; + } + - (BOOL) needsTransparency { - return self.contentView.layer.mask || self.colorKeyed || self.usePerPixelAlpha || + return self.shapeData || self.needsLayerTransparency || (gl_surface_mode == GL_SURFACE_BEHIND && [(WineContentView*)self.contentView hasGLDescendant]); }
- (void) checkTransparency { - if (![self isOpaque] && !self.needsTransparency) + if (!self.opaque && !self.needsTransparency) { self.shapeChangedSinceLastDraw = TRUE; - [[self contentView] setNeedsDisplay:YES]; + [self.contentView setNeedsDisplay:YES]; [self setBackgroundColor:[NSColor windowBackgroundColor]]; [self setOpaque:YES]; + /* Ensure WineApplicationController hasn't cut off mouse events */ + [self setIgnoresMouseEvents:NO]; } - else if ([self isOpaque] && self.needsTransparency) + else if (self.opaque && self.needsTransparency) { self.shapeChangedSinceLastDraw = TRUE; - [[self contentView] setNeedsDisplay:YES]; + [self.contentView setNeedsDisplay:YES]; [self setBackgroundColor:[NSColor clearColor]]; [self setOpaque:NO]; } + + [self.contentView.layer setOpaque:!self.needsLayerTransparency]; }
- (void) setShapeData:(NSData*)newShapeData @@ -2712,8 +2707,6 @@ - (void) setRetinaMode:(int)mode
[transform scaleBy:scale];
- [[self contentView] layer].mask.contentsScale = mode ? 2.0 : 1.0; - for (WineBaseView* subview in [self.contentView subviews]) { if ([subview isKindOfClass:[WineBaseView class]]) @@ -3319,6 +3312,7 @@ void macdrv_destroy_cocoa_window(macdrv_window w) WineWindow* window = (WineWindow*)w;
OnMainThread(^{ + window.surface = nil; window.closing = TRUE; [window doOrderOut]; [window close]; @@ -3485,14 +3479,13 @@ void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) /*********************************************************************** * macdrv_set_window_surface */ -void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) +void macdrv_set_window_surface(macdrv_window w, void *surface) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; WineWindow* window = (WineWindow*)w;
OnMainThread(^{ window.surface = surface; - window.surface_mutex = mutex; });
[pool release]; @@ -3659,9 +3652,7 @@ macdrv_view macdrv_create_view(CGRect rect)
view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(cgrect_mac_from_win(rect))]; [view setWantsLayer:YES]; - [view layer].minificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [view layer].magnificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [view layer].contentsScale = retina_on ? 2.0 : 1.0; + [view.layer setDrawsAsynchronously:YES]; [view setAutoresizesSubviews:NO]; [view setAutoresizingMask:NSViewNotSizable]; [view setHidden:YES]; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 3eecb26a01e..7b410fbdef0 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -209,7 +209,6 @@ extern DWORD CDECL macdrv_MsgWaitForMultipleObjectsEx(DWORD count, const HANDLE extern void activate_on_following_focus(void) DECLSPEC_HIDDEN; extern struct window_surface *create_surface(macdrv_window window, const RECT *rect, struct window_surface *old_surface, BOOL use_alpha) DECLSPEC_HIDDEN; -extern void set_window_surface(macdrv_window window, struct window_surface *window_surface) DECLSPEC_HIDDEN; extern void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha) DECLSPEC_HIDDEN; extern void surface_clip_to_visible_rect(struct window_surface *window_surface, const RECT *visible_rect) DECLSPEC_HIDDEN;
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index b0eb86133c4..34769771fa7 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -580,10 +580,11 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern void macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame) DECLSPEC_HIDDEN; extern void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame) DECLSPEC_HIDDEN; extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) DECLSPEC_HIDDEN; -extern void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) DECLSPEC_HIDDEN; +extern void macdrv_set_window_surface(macdrv_window w, void *surface) DECLSPEC_HIDDEN; extern CGImageRef create_surface_image(void *window_surface, CGRect *dirty_area, int color_keyed, uint8_t key_red, uint8_t key_green, uint8_t key_blue) DECLSPEC_HIDDEN; -extern int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) DECLSPEC_HIDDEN; +extern int surface_hit_test(void *window_surface, CGPoint point, int color_keyed, + uint8_t key_red, uint8_t key_green, uint8_t key_blue) DECLSPEC_HIDDEN; extern void macdrv_window_needs_display(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN; extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count) DECLSPEC_HIDDEN; extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index eed31229473..0eb1f09d417 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -64,7 +64,6 @@ struct macdrv_window_surface HRGN region; HRGN drawn; BOOL use_alpha; - RGNDATA *blit_data; struct shadow_surface *shadow; BYTE *bits; pthread_mutex_t mutex; @@ -317,27 +316,6 @@ static void shadow_cfdata_dealloc(void *ptr, void *info) shadow_bitmap_return(info); }
-/*********************************************************************** - * update_blit_data - */ -static void update_blit_data(struct macdrv_window_surface *surface) -{ - HeapFree(GetProcessHeap(), 0, surface->blit_data); - surface->blit_data = NULL; - - if (surface->drawn) - { - HRGN blit = CreateRectRgn(0, 0, 0, 0); - - if (CombineRgn(blit, surface->drawn, 0, RGN_COPY) > NULLREGION && - (!surface->region || CombineRgn(blit, blit, surface->region, RGN_AND) > NULLREGION) && - OffsetRgn(blit, surface->header.rect.left, surface->header.rect.top) > NULLREGION) - surface->blit_data = get_region_data(blit, 0); - - DeleteObject(blit); - } -} - /*********************************************************************** * macdrv_surface_lock */ @@ -401,7 +379,6 @@ static void macdrv_surface_set_region(struct window_surface *window_surface, HRG if (surface->region) DeleteObject(surface->region); surface->region = 0; } - update_blit_data(surface);
window_surface->funcs->unlock(window_surface); } @@ -433,7 +410,6 @@ static void macdrv_surface_flush(struct window_surface *window_surface) else surface->drawn = region; } - update_blit_data(surface); reset_bounds(&surface->bounds);
window_surface->funcs->unlock(window_surface); @@ -459,7 +435,7 @@ static void macdrv_surface_destroy(struct window_surface *window_surface) } if (surface->bits && surface->bits != MAP_FAILED) munmap(surface->bits, surface->info.bmiHeader.biSizeImage); - HeapFree(GetProcessHeap(), 0, surface->blit_data); + pthread_mutex_destroy(&surface->mutex); HeapFree(GetProcessHeap(), 0, surface); } @@ -515,7 +491,7 @@ struct window_surface *create_surface(macdrv_window window, const RECT *rect,
surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader); surface->info.bmiHeader.biWidth = width; - surface->info.bmiHeader.biHeight = -height; /* top-down */ + surface->info.bmiHeader.biHeight = height; /* bottom-up */ surface->info.bmiHeader.biPlanes = 1; surface->info.bmiHeader.biBitCount = 32; surface->info.bmiHeader.biSizeImage = get_dib_image_size(&surface->info); @@ -542,7 +518,6 @@ struct window_surface *create_surface(macdrv_window window, const RECT *rect, surface->drawn = 0; } } - update_blit_data(surface); surface->use_alpha = use_alpha; surface->shadow = shadow_surface_create(surface); if (!surface->shadow) goto failed; @@ -574,48 +549,6 @@ void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha if (surface) surface->use_alpha = use_alpha; }
-/*********************************************************************** - * set_window_surface - */ -void set_window_surface(macdrv_window window, struct window_surface *window_surface) -{ - struct macdrv_window_surface *surface = get_mac_surface(window_surface); - macdrv_set_window_surface(window, window_surface, surface ? &surface->mutex : NULL); -} - -/*********************************************************************** - * get_surface_blit_rects - * - * Caller must hold the surface lock. Indirectly returns the surface - * blit region rects. Returns zero if the surface has nothing to blit; - * returns non-zero if the surface does have rects to blit (drawn area - * which isn't clipped away by a surface region). - * - * IMPORTANT: This function is called from non-Wine threads, so it - * must not use Win32 or Wine functions, including debug - * logging. - */ -int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) -{ - struct macdrv_window_surface *surface = get_mac_surface(window_surface); - - if (rects && count) - { - if (surface->blit_data) - { - *rects = (const CGRect*)surface->blit_data->Buffer; - *count = surface->blit_data->rdh.nCount; - } - else - { - *rects = NULL; - *count = 0; - } - } - - return (surface->blit_data != NULL && surface->blit_data->rdh.nCount > 0); -} - /*********************************************************************** * create_surface_image * @@ -779,10 +712,59 @@ void surface_clip_to_visible_rect(struct window_surface *window_surface, const R { CombineRgn(surface->drawn, surface->drawn, region, RGN_AND); DeleteObject(region); - - update_blit_data(surface); } }
window_surface->funcs->unlock(window_surface); } + +/*********************************************************************** + * surface_hit_test + * + * Performs a per-pixel hit test on the given surface. Returns FALSE if + * the chosen pixel is transparent or keyed out, TRUE if the pixel is + * clickable. + * + * IMPORTANT: This function is called from non-Wine threads, so it + * must not use Win32 or Wine functions, including debug + * logging. + */ +int surface_hit_test(void *window_surface, CGPoint point, int color_keyed, + uint8_t key_red, uint8_t key_green, uint8_t key_blue) +{ + struct macdrv_window_surface *surface = get_mac_surface(window_surface); + DWORD key = (key_red << 16) | (key_green << 8) | (key_blue); + DWORD pixel; + int surface_width, bytes_per_row; + /* Note: coordinates can be non-integers. Truncate. */ + int point_x = point.x, point_y = point.y; + int retval = TRUE; + + if (!surface) + return TRUE; + + pthread_mutex_lock(&surface->mutex); + surface_width = surface->header.rect.right - surface->header.rect.left; + bytes_per_row = get_dib_stride(surface_width, 32); + + if (!surface->use_alpha && !color_keyed) + /* Opaque surface always succeeds */ + goto done; + + if (point_x < surface->header.rect.left || point_x >= surface->header.rect.right + || point_y < surface->header.rect.top || point_y >= surface->header.rect.bottom) + { + retval = FALSE; + goto done; + } + + pixel = *(DWORD*)(surface->bits + (point_x - surface->header.rect.left) * 4 + + (surface->header.rect.bottom - point_y) * bytes_per_row); + + retval = !((color_keyed && (pixel & 0x00FFFFFF) == key) + || (surface->use_alpha && (pixel & 0xFF000000) == 0)); + +done: + pthread_mutex_unlock(&surface->mutex); + return retval; +} diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 9177f493a5f..dba87df37de 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1899,7 +1899,7 @@ BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO * if (!surface || !EqualRect(&surface->rect, &rect)) { data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE); - set_window_surface(data->cocoa_window, data->surface); + macdrv_set_window_surface(data->cocoa_window, data->surface); if (surface) window_surface_release(surface); surface = data->surface; if (data->unminimized_surface) @@ -2139,7 +2139,7 @@ void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, } else { - set_window_surface(data->cocoa_window, surface); + macdrv_set_window_surface(data->cocoa_window, surface); if (data->unminimized_surface) { window_surface_release(data->unminimized_surface);