crtc->{x,y} is always 0 when xf86DefaultScreenLimits() is called, so we
calculate too small an area for the initial framebuffer and force a resize
to happen.
This commit fixes the code to use desired{X,Y} instead, which contains the
initial output positions.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit f7af00e9f0)
Commit 77c7a64e88 was introduced to fix
a cursor off by one on Intel hw, however it also move the whole crtc
into an off by one position and you could see gnom-eshell overlapping.
This commit reverts that and instead fixes the cursor hotspot
translation to work like pixman does. We add 0.5 to the cursor vector
before translating, and floor the value afterwards.
Thanks to Soeren (ssp) for pointing out where the real problem was
after explaning how pixman translates points.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 80d1a548d6)
Behaviour of earlier X servers was to deliver the ButtonPress event
unconditionally, regardless of the actual event mask being set. This is
documented in the protocol:
"This request establishes a passive grab. In the future, the pointer is
actively grabbed as described in GrabPointer, the last-pointer-grab time is
set to the time at which the button was pressed (as transmitted in the
ButtonPress event), and the ButtonPress event is reported if all of the
following conditions are true:
<list of conditions, event mask is not one of them>"
Thus, a GrabButton event will always deliver the button press event, a
GrabKey always the key press event, etc. Same goes for XI and XI2.
Reproducible with a simple client requesting a button grab in the form of:
XGrabButton(dpy, AnyButton, AnyModifier, win, True, ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None);
On servers before MPX/XI2, the client will receive a button press and
release event. On current servers, the client receives only the release.
Clients that expect the press event to be delivered unconditionally.
XTS Xlib13 XGrabButton 5/39 now passes.
This reverts commit 48585bd1e3.
Effectively reverts commit 1c612acca8 as well,
the code introduced with 1c612 is not needed anymore.
Conflicts:
dix/events.c
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 1884db430a)
Without this patch, any negative valuator value is wrong when returned
from XQueryDeviceState(). This is a regression from at least xserver
1.4.
Valuator data is set in dix/getevents.c:set_valuators() by copying
signed int values into an unsigned int field
DeviceEvent.valuators.data.
That data is converted into a double with an implicit cast by
assignment to axisVal[i] in Xi/exevents.c:UpdateDeviceState().
That double is converted back to a signed int in
queryst.c:ProcXQueryDeviceState(). If the original value in
set_valuators() is negative, the double value will be > 2^31 and the
conversion back to a signed int is undefined. (Although I
consistently see the value -2^31.)
Fix this by changing the definition of DeviceEvent.valuators.data from
uint32_t to int32_t.
Signed-off-by: Joe Shaw <joeshaw@litl.com>
Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit e354ccac36)
These have the same default, but if you specify something different with
-s on the command line, only the screensaver time is changed. As DPMS
is usually what's desired, change it to match.
Signed-off-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 2a763c9023)
If a client sends a big request that's too big (i.e. bigger than
maxBigRequestSize << 2 bytes), the server just disconnects it. This makes the
client receive SIGPIPE the next time it tries to send something.
The X Test Suite sends requests that are too big when the test specifies the
TOO_LONG test type. When the client receives SIGPIPE, XTS marks it as
UNRESOLVED, which counts as a failure.
Instead, remember how long the request is supposed to be and then return that
size. Dispatch() checks the length and sends BadLength to the client. Then,
whenever oci->ignoreBytes is nonzero, ignore the data read instead of trying to
process it as a request.
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit cf88363db0)
Because some EnterVT code needs to remove it self from the
call chain, we need to fix all of the wrappers to correctly
unwrap/rewrap during the call chain. This is a follow-on to the fix
for bug 27114 in commit 68a9ee8370.
Signed-off-by: Keith Packard <keithp@keithp.com>
Tested-by: Jesse Barnes <jesse.barnes@intel.com>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Reviewed-by: Tiago Vignatti <tiago.vignatti@nokia.com>
(cherry picked from commit d75e8146c4, and
conflict from b618705 fixed up)
Signed-off-by: Julien Cristau <jcristau@debian.org>
(cherry picked from commit 3336e1f7f3)
When resetting the server, pScrn->EnterVT must be unwrapped or the
next server generation will end up wrapping the wrapper and causing an
infinite recursion on EnterVT.
Signed-off-by: Keith Packard <keithp@keithp.com>
Tested-by: Michael Stapelberg <michael+freedesktop@stapelberg.de>
(cherry picked from commit 68a9ee8370)
ProcDRI2Dispatch uses LocalClient to determine if it's safe to respond
to a client that has made DRI2 requests which aren't sensible for
remote clients (anything but version). When the client has disappeared
mid-request stream (e.g. as a result of a kill -9, or a client-side
bug), LocalClient causes the X server to follow suit, as
((OsCommPtr)client->osPrivate)->trans_conn is NULL at this point.
The simple and obvious fix is to just return "not local" when
trans_conn is NULL, which fixes the crash I was seeing; however Keith
Packard pointed out that just checking trans_conn isn't enough;
quoting Keith:
"This looks almost right to me -- I reviewed the os code to see when
_XSERVTransClose is called (which is what frees the trans_conn data) and
found that every place which called that immediately set trans_conn to
NULL, except for the call in CloseDownFileDescriptor which is only
called from CloseDownConnection and which is immediately followed by
freeing the OsCommRec and setting client->osPrivate to NULL. So, I'd
suggest checking client->osPrivate in addition to the above check."
Signed-off-by: Simon Farnsworth <simon.farnsworth@onelan.com>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 660f6ab549)
When the parser sees the "keyboard" driver, it automatically (and
silently) replaces it with the constant string "kbd".
Everybody else uses malloc'd memory for the driver name, so input
device closure assumes it can use free.
Free val.str, so this crash doesn't turn into a memory leak. Whew.
Signed-off-by: Jesse Adkins <jesserayadkins@gmail.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit bce12f2956)
A window with either dimension > 32767 can be positioned such that
coordinates > 32767 are visible on the screen. Attempts to draw to
those pixels will generate coordinates wrapped around to negative
values.
The optimized clipping macro, 'isClipped', in fbbits.h, computes
clipping in window space rather than screen space using int16 values,
and so it too has coordinates wrapped around to negative values and
hence ends up accepting the wrapped drawing coordinates.
Two possible fixes for this problem
1) Detect wrapped region coordinates and clip those to 32767.
2) Detect negative incoming coordinates and reject those
This patch takes the second approach as it is much shorter, simply
detecting when either X or Y incoming coordinate is negative, which
can never be 'within' any drawable.
Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
(cherry picked from commit 3e56efcfb6)
A simple hack to accommodate various EDID who have detailed modes that
exceed the EDID's max pixel clock. The pixel clock is only defined in
units of 10MHz and often appears as the maximum pixel code of the
detailed modes, rounded to the nearest 10MHz. Adjusting the max_clock to
include an extra 5MHz prevents the parser from rejecting the detailed
modes.
The kernel uses the same fuzz and by including it in X we can use the
same modes in X as for the console.
Fixes:
Bug 23833 - X uses different refresh rate to that set by kernel module
https://bugs.freedesktop.org/show_bug.cgi?id=23833
In the future, we will want to try harder to keep the KMS modes but at
the same time we need to apply the restrictions as specified by the
user's configuration, and need to fill in modes for fullscreen games on
fixed-mode panels.
Reported-and-tested-by: Fabio Pedretti <fabio.ped@libero.it>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 951605b466)
Signed-off-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Julien Cristau <jcristau@debian.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 5725849a1b)
The callback data passed by reference to the hook was allocated on stack
within the scope of the case statement. The compiler is free to reuse
any of that stack space whilst making the function call so we may end up
passing garbage into the callback.
References:
Bug 18451 - Xorg server 1.5.2 SEGV during XFixesGetCursorImage()
https://bugs.freedesktop.org/show_bug.cgi?id=18451
v2: Drop the unrelated hunk that snuck in when ammending the commit
message.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 6dae7f3792)
We were incorrectly NULLing out pDraw in __GLXDrawable instead of ours in
__GLXAquaDrawable. (we should refactor to eliminate this redundancy later)
This was causing http://xquartz.macosforge.org/trac/ticket/426
This was benign until commit f0006aa58f
The root cause of this change was fed7ccc481ad1caaa518cafe944c2327a5d0b6c65
Signed-off-by: Jeremy Huddleston <jeremyhu@apple.com>
(cherry picked from commit 98f90145d7)
Fixes regression introduced in 9de0e31746
Signed-off-by: Jeremy Huddleston <jeremyhu@apple.com>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit ba1f1f9d9e)
If the native root window isn't resized as well, we will likely crash the
next time we draw to the root. On OS X, this can be seen by:
1) Put the display preferences in the menu bar and set X11's preferences so you
can access the menu bar in fullscreen mode
2) Set the resolution of your screen lower than normal.
3) Start X11 in fullscreen mode. The root window will cover the screen as
expected.
4) Use the menu bar to increase the resolution of the display. The root
window will now cover the old area and not the full screen, but
'xwininfo -root' will report the full width.
5) Run 'xsetroot -solid red', and we have the crash you mention above.
Leaving/entering fullscreen after #4 will fix the problem. This is because the
WINREC is erased when we leave fullscreen mode and it is recreated upon
re-entry:
RootlessUpdateRooted(FALSE)
RootlessDisableRoot(screenInfo.screens[0])
RootlessDestroyFrame (pRoot, winRec);
RootlessUpdateRooted(TRUE)
RootlessEnableRoot(screenInfo.screens[0])
RootlessEnsureFrame(screenInfo.screens[0]->pRoot)
creates a new WINREC...
Signed-off-by: Jan Hauffa <hauffa@in.tum.de>
Reviewed-by: Jeremy Huddleston <jeremyhu@apple.com>
Acked-By: Jon TURNEY <jon.turney@dronecode.org.uk>
Tested-by: Jeremy Huddleston <jeremyhu@apple.com>
(cherry picked from commit 95756f410c)
When ResetCurrentRequest is called, or IgnoreClient is called when a
client has input pending, IgnoredClientsWithInput will be set. However,
a subsequent IgnoreClient request will clear the client fd from that fd
set, potentially causing the client to hang.
So add an Ignore/Attend count, and only apply the ignore logic on the
first ignore and the attend logic on the last attend. This is
consistent with the comments for these functions; callers must pair
them.
Fixes https://bugs.freedesktop.org/show_bug.cgi?id=27035.
Reviewed-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
Detect if a drawable has been moved from an original crtc to a new crtc
with a lower current vblank count than the original crtc inbetween
glXSwapBuffers() calls. Reinitialize drawable's last_swap_target
before scheduling next swap if such a move has taken place.
last_swap_target defines the baseline for scheduling the next swap.
If a movement between crtc's is not taken into account, the swap may
schedule for a vblank count on the new crtc far in the future, resulting
in a apparent "hang" of the drawable for a long time.
Fixes Bugzilla bug #28383.
Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 75beadd766)
In case you want to copy a region with source = dest, you have the same pixmap
as source and dest.
At the end of exaPixmapIsOffscreen_classic() the devPrivate.ptr is reset to
NULL (look at the sources).
Now this is what happens in ExaCheckCopyNtoN:
exaPrepareAccess( pDst );
Calls IsOffscreen()
sets devPrivate.ptr to NULL
sets up devPrivate.ptr to real pointer
Everything OK
exaPrepareAccess( pSrc );
Calls IsOffscreen()
sets devPrivate.ptr to NULL
BAILS OUT CAUSE OF NESTED OPERATION SINCE DST EQUALS SRC
We end up with devPrivate.ptr as NULL, and that is clearly wrong.
In particular this fixes a segfault when using the psb driver (bug 28077)
Signed-off-by: Éric Piel <eric.piel@tremplin-utc.net>
Reviewed-by: Michel Dänzer <michel@daenzer.net>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 7e8f100121)
The modifier key count is maintained by the XKB layer and
increased/decreased for all modifiers that set state.
Test case, MD/SD modifier key count in comment:
1. keyboard 1: press and hold Shift_L # SD:1 MD:1
2. keyboard 2: press and release Shift_L # SD:1,0 MD:1,0
<class copy happens> # SD:1 MD:1
3. keyboard 1: release Shift_L # SD:0 MD:1
4. keyboard 1: press and release Shift_L # SD:1,0 MD:2,1
The modifier is now logically down on the MD but not on keyboard 1 or
keyboard 2.
XKB is layered in before the DIX, it increases/decreases the modifier key
count accordingly. In the above example, during (2), the MD gets the key
release and thus clears the modifier bit. (3) doesn't forward the release to
the MD because it is already cleared. The copy of modifierKeysDown when the
lastSlave changes however increases the counter for the held key. On (4),
the press and release are both forwarded to the MD, causing a offset by 1
and thus do not clear the logical modifier state.
X.Org Bug 25480 <http://bugs.freedesktop.org/show_bug.cgi?id=25480>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Daniel Stone <daniel@fooishbar.org>
(cherry picked from commit dc614484f9)
DRI2WaitSBC() didn't block if requested targetSBC wasn't yet reached.
Instead it returned a xreply with uninitialized junk return values, then
blocked the connection until targetSBC was reached.
Therefore the client didn't block, but continued with bogus return
values from glXWaitForSbcOML.
This patch fixes the problem by implementing DRI2WaitSBC similar
to the clean and proven DRI2WaitMSC implementation.
Signed-off-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit b3548612c7)
Conflicts:
hw/xfree86/dri2/dri2ext.c
Classic strlen/strcpy mistake of
foo = malloc(strlen(bar));
strcpy(foo, bar);
Testcase: valgrind Xephyr :1
==8591== Invalid write of size 1
==8591== at 0x4A0638F: strcpy (mc_replace_strmem.c:311)
==8591== by 0x605593: _XkbCopyGeom (xkbUtils.c:1994)
==8591== by 0x605973: XkbCopyKeymap (xkbUtils.c:2118)
==8591== by 0x6122B3: InitKeyboardDeviceStruct (xkbInit.c:560)
==8591== by 0x4472E2: CoreKeyboardProc (devices.c:577)
==8591== by 0x447162: ActivateDevice (devices.c:530)
==8591== by 0x4475D6: InitCoreDevices (devices.c:672)
==8591== by 0x4449EE: main (main.c:254)
==8591== Address 0x6f96505 is 0 bytes after a block of size 53 alloc'd
==8591== at 0x4A0515D: malloc (vg_replace_malloc.c:195)
==8591== by 0x6054B7: _XkbCopyGeom (xkbUtils.c:1980)
==8591== by 0x605973: XkbCopyKeymap (xkbUtils.c:2118)
==8591== by 0x6122B3: InitKeyboardDeviceStruct (xkbInit.c:560)
==8591== by 0x4472E2: CoreKeyboardProc (devices.c:577)
==8591== by 0x447162: ActivateDevice (devices.c:530)
==8591== by 0x4475D6: InitCoreDevices (devices.c:672)
==8591== by 0x4449EE: main (main.c:254)
Reported-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by-and-apologised-for: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 7f19a7a6e9)
Conflicts:
xkb/xkbUtils.c
miDbePositionWindow allocates two pixmaps: a front buffer, and a back buffer.
If the buffers are supposed to be initialized, it validates a GC against the
front buffer, then uses it to fill and/or copy both the front buffer *and* the
back buffer, without revalidating. If the acceleration architecture needs
different GC funcs for the two pixmaps -- for example if allocation of the front
buffer exhausted video memory -- then this can cause crashes because the GC is
not validated for the back buffer pixmap.
Fix this by performing the rendering for the front buffer first, then
revalidating against the back buffer before performing the back buffer
rendering.
Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Reviewed-by: Jamey Sharp <jamey@minilop.net>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 1304b8b27c)
We just never initialised the malloced value.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 91a6359caf)
Makes the use of IsMaster in ProcChangeKeyboardControl consistent with other
similar loops.
Signed-off-by: Nicolas George <nicolas.george@normalesup.org>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
(cherry picked from commit 968a79dcf5)
Reverts part of the effects of 518f3b189b,
"mi: don't thrash resources when displaying the software cursor across
screens". The per-screen cache is preserved, and the GCs are still
allocated eagerly, but now it doesn't construct pRootPicture until
somebody attempts to draw an ARGB cursor.
I noticed crashes in Xnest, which doesn't support the RENDER extension,
but I suspect other DDXes that support disabling that extension would
have had issues as well.
Signed-off-by: Jamey Sharp <jamey@minilop.net>
Reviewed-by: Pierre-Loup A. Griffais <pgriffais@nvidia.com>
(cherry picked from commit bf78e11839)
Some pixmaps (window pixmaps and scratch pixmaps) don't have the
drawable->id set and thus DRI2 gets confused when using that field
for looking up the DRI2 drawable. Go back to using privates for getting
at the DRI2 drawable from a DrawablePtr. We need to keep the resource
tracking in place so we can remove the DRI2 drawable when the X resource
it was created for goes away. Additionally, we also now track the DRI2
drawable using a client XID so we can reclaim the DRI2 drawable even if
the client goes before the drawable and doesn't destroy the DRI2 drawable.
Tested-by: Owen W. Taylor <otaylor@fishsoup.net>
Signed-off-by: Kristian Høgsberg <krh@bitplanet.net>
(cherry picked from commit 9de0e31746)
Conflicts:
hw/xfree86/dri2/dri2.c
If we use the #define'd version from dri_interface.h, the server will
require at least that version of the extension. If we're compiling against
a dri_interface.h with a newer version we don't really require, glxdri2
will require a too high version of the extension.
The right approach is to just hard-code the version we need instead of
using the #defines.
Signed-off-by: Kristian Høgsberg <krh@bitplanet.net>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
(cherry picked from commit 4a8a615d01)
FreeResource() keeps clientTable[cid].elements up to date with the
number of resources allocated to the client. The other free
resource functions (FreeResourceByType(),
FreeClientNeverRetainResources() and FreeClientResources()) don't
maintain this invariant.
Typically, the only consequence is that the element count is too high
and we end up allocating the hash table bigger than necessary. However,
FreeResource() also relies on the element count to restart the search if
the list of resources has been changed during a resource destruction
callback. Since FreeResourceByType() doesn't update the count, if we call
that from a resource destruction callback from FreeResource(), the
loop isn't restarted and we end up following an invalid next pointer.
Furthermore, LookupClientResourceComplex() and
FreeClientNeverRetainResources() don't use the element count to detect
if a callback deleted a resource and may end up following an invalid
next pointer if the resource system is called into recursively.
Signed-off-by: Kristian Høgsberg <krh@bitplanet.net>
Reviewed-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 6d7ba5e0fc)
attr->tags is an array of strings (null-terminated). When matching, match
against each string instead of each [i,end] substring in the first tag.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jamey Sharp <jamey@minilop.net>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit b5e0f6d8f4)
When Xorg is started on display :0, this ioctl is called to grant the
user the rights traditionally associated with /dev/console (before VT
support was added), such as access to local peripheral devices.
Also adds a Solaris-specific -C flag to force starting on /dev/console
instead of /dev/vt*, allowing programs like xterm -C to access the
console device.
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 989db930d7)
- Note that -br is now default.
- Move -bs after -br for alphabetical ordering.
- Remove -config option that's been hidden in "ignore" section,
since ajax removed the -config code a couple years back.
- Add -nocursor option.
- Add xinput & xrandr to list of runtime server control programs
- Replace XDarwin with Xquartz in list of Xservers
Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit 7b09335a46)
The code this comment was referring to was removed in
8b5086250a "Eliminate bogus event resizing."
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
(cherry picked from commit cf4f3d0518)