mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-11-17 23:42:20 +00:00
Compare commits
43 Commits
B3-rc1
...
Release/B3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2973319bff | ||
|
|
ec921d7f39 | ||
|
|
637a7625d2 | ||
|
|
32d8a47cd9 | ||
|
|
b4787fcfd1 | ||
|
|
e6ebcec689 | ||
|
|
ff0a859ceb | ||
|
|
1b48ac842a | ||
|
|
a702c912ae | ||
|
|
acc3298344 | ||
|
|
25e74301be | ||
|
|
327d472d64 | ||
|
|
e951aaad2d | ||
|
|
bbfe5aea37 | ||
|
|
0d28ea160e | ||
|
|
4fbaf18c89 | ||
|
|
c91b7f647d | ||
|
|
1761ea2b9b | ||
|
|
fb916cbac1 | ||
|
|
b97130cf20 | ||
|
|
05f2305fa0 | ||
|
|
b76fedeb67 | ||
|
|
6b5842d2ff | ||
|
|
7e15ec5e66 | ||
|
|
1808adc2de | ||
|
|
e2e49bce13 | ||
|
|
0d7be70b56 | ||
|
|
6b0699e664 | ||
|
|
9e96156912 | ||
|
|
837858c214 | ||
|
|
3783a25211 | ||
|
|
941c651fad | ||
|
|
f9ec32b255 | ||
|
|
8caf951c41 | ||
|
|
ef54e1be7f | ||
|
|
4c1893fe20 | ||
|
|
086f73721d | ||
|
|
202739c5be | ||
|
|
88b15cb3fe | ||
|
|
6990d7f7e3 | ||
|
|
9941a4bb83 | ||
|
|
d610aaf2cf | ||
|
|
908aa84599 |
13
.github/issue_template.md
vendored
13
.github/issue_template.md
vendored
@@ -5,8 +5,8 @@ If you are looking for help or support please use one of the following methods
|
||||
Create a New Topic on the Level1Tech's forum under the Looking Glass category:
|
||||
* https://forum.level1techs.com/c/software/lookingGlass/142
|
||||
|
||||
Ask for help in #looking-glass in the VFIO discord server
|
||||
* https://discord.gg/4ahCn4c
|
||||
Ask for help in the Looking Glass discord server
|
||||
* https://discord.gg/52SMupxkvt
|
||||
|
||||
*Issues that are not bug reports or feature requests will be closed & ignored*
|
||||
|
||||
@@ -40,12 +40,9 @@ PASTE CLIENT OUTPUT HERE
|
||||
```
|
||||
|
||||
The entire (not truncated) log file from the host application (if applicable).
|
||||
To obtain this locate the log file on your system, it will be in one of the
|
||||
following two locations depending on how you are launching the Looking Glass Host
|
||||
application:
|
||||
Normally, this is found on the guest system at:
|
||||
|
||||
* C:\Windows\Temp\looking-glass.txt
|
||||
* C:\Users\YOUR_USER\AppData\Local\Temp\looking-glass.txt
|
||||
%ProgramData%\Looking Glass (host)\looking-glass-host.txt
|
||||
|
||||
This log may be quite long, please delete the file first and then proceed to
|
||||
launch the host and reproduce the issue so that the log only contains the
|
||||
@@ -56,7 +53,7 @@ pertinent information.
|
||||
PASTE HOST LOG FILE CONTENTS HERE
|
||||
```
|
||||
|
||||
If the client is unexpetedly exiting without a backtrace, please provide one via
|
||||
If the client is unexpectedly exiting without a backtrace, please provide one via
|
||||
gdb with the command `thread apply all bt`. If you are unsure how to do this
|
||||
please watch the video below on how to perform a Debug build and generate this
|
||||
backtrace.
|
||||
|
||||
@@ -51,11 +51,12 @@ https://looking-glass.io/downloads
|
||||
|
||||
## Web
|
||||
|
||||
https://forum.level1techs.com/t/looking-glass-triage/130952
|
||||
https://forum.level1techs.com/c/software/lookingglass/142
|
||||
|
||||
## Discord
|
||||
|
||||
https://discord.gg/4ahCn4c
|
||||
* Looking Glass: https://discord.gg/52SMupxkvt
|
||||
* VFIO: https://discord.gg/4ahCn4c
|
||||
|
||||
## IRC
|
||||
|
||||
|
||||
@@ -391,9 +391,18 @@ static void relativePointerMotionHandler(void * data,
|
||||
wl_fixed_t dxW, wl_fixed_t dyW, wl_fixed_t dxUnaccelW,
|
||||
wl_fixed_t dyUnaccelW)
|
||||
{
|
||||
double dxUnaccel = wl_fixed_to_double(dxUnaccelW);
|
||||
double dyUnaccel = wl_fixed_to_double(dyUnaccelW);
|
||||
app_handleMouseGrabbed(dxUnaccel, dyUnaccel);
|
||||
double dx, dy;
|
||||
if (app_cursorWantsRaw())
|
||||
{
|
||||
dx = wl_fixed_to_double(dxUnaccelW);
|
||||
dy = wl_fixed_to_double(dyUnaccelW);
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = wl_fixed_to_double(dxW);
|
||||
dy = wl_fixed_to_double(dyW);
|
||||
}
|
||||
app_handleMouseGrabbed(dx, dy);
|
||||
}
|
||||
|
||||
static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
|
||||
@@ -635,11 +644,12 @@ static void dataOfferHandleOffer(void * data, struct wl_data_offer * offer,
|
||||
const char * mimetype)
|
||||
{
|
||||
enum LG_ClipboardData type = mimetypeToCbType(mimetype);
|
||||
// Oftentimes we'll get text/html alongside text/png, but would prefer to send
|
||||
// image/png. In general, prefer images over text content.
|
||||
// We almost never prefer text/html, as that's used to represent rich text.
|
||||
// Since we can't copy or paste rich text, we should instead prefer actual
|
||||
// images or plain text.
|
||||
if (type != LG_CLIPBOARD_DATA_NONE &&
|
||||
(wcb.stashedType == LG_CLIPBOARD_DATA_NONE ||
|
||||
wcb.stashedType == LG_CLIPBOARD_DATA_TEXT))
|
||||
strstr(wcb.stashedMimetype, "html")))
|
||||
{
|
||||
wcb.stashedType = type;
|
||||
if (wcb.stashedMimetype)
|
||||
|
||||
@@ -261,6 +261,7 @@ static bool x11GetProp(LG_DSProperty prop, void *ret)
|
||||
maxSamples = samples;
|
||||
}
|
||||
|
||||
XFree(visuals);
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
*(int*)ret = maxSamples;
|
||||
@@ -336,12 +337,14 @@ static bool x11EventFilter(SDL_Event * event)
|
||||
return true;
|
||||
|
||||
XIFocusOutEvent *xie = cookie->data;
|
||||
if (xie->mode != NotifyNormal && xie->mode != XINotifyWhileGrabbed)
|
||||
if (xie->mode != XINotifyNormal &&
|
||||
xie->mode != XINotifyWhileGrabbed &&
|
||||
xie->mode != XINotifyUngrab)
|
||||
return true;
|
||||
|
||||
x11.focused = true;
|
||||
app_updateCursorPos(xie->event_x, xie->event_y);
|
||||
app_handleFocusEvent(true);
|
||||
x11.focused = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -351,7 +354,9 @@ static bool x11EventFilter(SDL_Event * event)
|
||||
return true;
|
||||
|
||||
XIFocusOutEvent *xie = cookie->data;
|
||||
if (xie->mode != NotifyNormal && xie->mode != XINotifyWhileGrabbed)
|
||||
if (xie->mode != XINotifyNormal &&
|
||||
xie->mode != XINotifyWhileGrabbed &&
|
||||
xie->mode != XINotifyGrab)
|
||||
return true;
|
||||
|
||||
app_updateCursorPos(xie->event_x, xie->event_y);
|
||||
@@ -470,6 +475,9 @@ static bool x11EventFilter(SDL_Event * event)
|
||||
{
|
||||
XIDeviceEvent *device = cookie->data;
|
||||
app_updateCursorPos(device->event_x, device->event_y);
|
||||
|
||||
if (!x11.pointerGrabbed)
|
||||
app_handleMouseNormal(0.0, 0.0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -571,6 +579,25 @@ static bool x11EventFilter(SDL_Event * event)
|
||||
}
|
||||
}
|
||||
|
||||
static void x11PrintGrabError(const char * type, int dev, Status ret)
|
||||
{
|
||||
const char * errStr;
|
||||
switch(ret)
|
||||
{
|
||||
case AlreadyGrabbed : errStr = "AlreadyGrabbed" ; break;
|
||||
case GrabNotViewable: errStr = "GrabNotViewable"; break;
|
||||
case GrabFrozen : errStr = "GrabFrozen" ; break;
|
||||
case GrabInvalidTime: errStr = "GrabInvalidTime"; break;
|
||||
default:
|
||||
errStr = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("XIGrabDevice failed for %s dev %d with 0x%x (%s)",
|
||||
type, dev, ret, errStr);
|
||||
|
||||
}
|
||||
|
||||
static void x11GrabPointer(void)
|
||||
{
|
||||
if (x11.pointerGrabbed)
|
||||
@@ -588,18 +615,22 @@ static void x11GrabPointer(void)
|
||||
XISetMask(mask.mask, XI_RawMotion );
|
||||
XISetMask(mask.mask, XI_Motion );
|
||||
|
||||
XIGrabDevice(
|
||||
Status ret = XIGrabDevice(
|
||||
x11.display,
|
||||
x11.pointerDev,
|
||||
x11.window,
|
||||
CurrentTime,
|
||||
None,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
false,
|
||||
XIGrabModeAsync,
|
||||
XIGrabModeAsync,
|
||||
XINoOwnerEvents,
|
||||
&mask);
|
||||
|
||||
XSync(x11.display, False);
|
||||
if (ret != Success)
|
||||
{
|
||||
x11PrintGrabError("pointer", x11.pointerDev, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
x11.pointerGrabbed = true;
|
||||
}
|
||||
@@ -630,18 +661,22 @@ static void x11GrabKeyboard(void)
|
||||
XISetMask(mask.mask, XI_RawKeyPress );
|
||||
XISetMask(mask.mask, XI_RawKeyRelease);
|
||||
|
||||
XIGrabDevice(
|
||||
Status ret = XIGrabDevice(
|
||||
x11.display,
|
||||
x11.keyboardDev,
|
||||
x11.window,
|
||||
CurrentTime,
|
||||
None,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
false,
|
||||
XIGrabModeAsync,
|
||||
XIGrabModeAsync,
|
||||
XINoOwnerEvents,
|
||||
&mask);
|
||||
|
||||
XSync(x11.display, False);
|
||||
if (ret != Success)
|
||||
{
|
||||
x11PrintGrabError("keyboard", x11.keyboardDev, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
x11.keyboardGrabbed = true;
|
||||
}
|
||||
|
||||
@@ -36,19 +36,21 @@ struct Inst
|
||||
|
||||
static bool lgf_sdl_create(LG_FontObj * opaque, const char * font_name, unsigned int size)
|
||||
{
|
||||
if (g_initCount++ == 0)
|
||||
bool ret = false;
|
||||
|
||||
if (g_initCount == 0)
|
||||
{
|
||||
if (TTF_Init() < 0)
|
||||
{
|
||||
DEBUG_ERROR("TTF_Init Failed");
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
g_fontConfig = FcInitLoadConfigAndFonts();
|
||||
if (!g_fontConfig)
|
||||
{
|
||||
DEBUG_ERROR("FcInitLoadConfigAndFonts Failed");
|
||||
return false;
|
||||
goto fail_init;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,50 +58,95 @@ static bool lgf_sdl_create(LG_FontObj * opaque, const char * font_name, unsigned
|
||||
if (!*opaque)
|
||||
{
|
||||
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(struct Inst));
|
||||
return false;
|
||||
goto fail_config;
|
||||
}
|
||||
memset(*opaque, 0, sizeof(struct Inst));
|
||||
|
||||
memset(*opaque, 0, sizeof(struct Inst));
|
||||
struct Inst * this = (struct Inst *)*opaque;
|
||||
|
||||
if (!font_name)
|
||||
if (!font_name)
|
||||
font_name = "FreeMono";
|
||||
|
||||
FcPattern * pat = FcNameParse((const FcChar8*)font_name);
|
||||
FcConfigSubstitute (g_fontConfig, pat, FcMatchPattern);
|
||||
if (!pat)
|
||||
{
|
||||
DEBUG_ERROR("FCNameParse failed");
|
||||
goto fail_opaque;
|
||||
}
|
||||
|
||||
FcConfigSubstitute(g_fontConfig, pat, FcMatchPattern);
|
||||
FcDefaultSubstitute(pat);
|
||||
FcResult result;
|
||||
FcChar8 * file = NULL;
|
||||
FcPattern * font = FcFontMatch(g_fontConfig, pat, &result);
|
||||
FcPattern * match = FcFontMatch(g_fontConfig, pat, &result);
|
||||
|
||||
if (font && (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch))
|
||||
if (!match)
|
||||
{
|
||||
DEBUG_ERROR("FcFontMatch Failed");
|
||||
goto fail_parse;
|
||||
}
|
||||
|
||||
if (FcPatternGetString(match, FC_FILE, 0, &file) == FcResultMatch)
|
||||
{
|
||||
this->font = TTF_OpenFont((char *)file, size);
|
||||
if (!this->font)
|
||||
{
|
||||
DEBUG_ERROR("TTL_OpenFont Failed");
|
||||
return false;
|
||||
goto fail_match;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_ERROR("Failed to locate the requested font: %s", font_name);
|
||||
return false;
|
||||
goto fail_match;
|
||||
}
|
||||
|
||||
++g_initCount;
|
||||
ret = true;
|
||||
|
||||
fail_match:
|
||||
FcPatternDestroy(match);
|
||||
|
||||
fail_parse:
|
||||
FcPatternDestroy(pat);
|
||||
|
||||
return true;
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
fail_opaque:
|
||||
free(this);
|
||||
*opaque = NULL;
|
||||
|
||||
fail_config:
|
||||
if (g_initCount == 0)
|
||||
{
|
||||
FcConfigDestroy(g_fontConfig);
|
||||
g_fontConfig = NULL;
|
||||
}
|
||||
|
||||
fail_init:
|
||||
if (g_initCount == 0)
|
||||
TTF_Quit();
|
||||
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void lgf_sdl_destroy(LG_FontObj opaque)
|
||||
{
|
||||
struct Inst * this = (struct Inst *)opaque;
|
||||
|
||||
if (this->font)
|
||||
TTF_CloseFont(this->font);
|
||||
free(this);
|
||||
|
||||
if (--g_initCount == 0)
|
||||
{
|
||||
FcConfigDestroy(g_fontConfig);
|
||||
g_fontConfig = NULL;
|
||||
|
||||
TTF_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
static LG_FontBitmap * lgf_sdl_render(LG_FontObj opaque, unsigned int fg_color, const char * text)
|
||||
|
||||
@@ -33,7 +33,8 @@ make_object(
|
||||
|
||||
add_library(renderer_EGL STATIC
|
||||
egl.c
|
||||
debug.c
|
||||
dynprocs.c
|
||||
egldebug.c
|
||||
shader.c
|
||||
texture.c
|
||||
model.c
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
||||
https://looking-glass.hostfission.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void egl_debug_printf(char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
|
||||
GLenum error = glGetError();
|
||||
switch(error)
|
||||
{
|
||||
case GL_NO_ERROR:
|
||||
fprintf(stderr, " (GL_NO_ERROR)\n");
|
||||
break;
|
||||
|
||||
case GL_INVALID_ENUM:
|
||||
fprintf(stderr, " (GL_INVALID_ENUM)\n");
|
||||
break;
|
||||
|
||||
case GL_INVALID_VALUE:
|
||||
fprintf(stderr, " (GL_INVALID_VALUE)\n");
|
||||
break;
|
||||
|
||||
case GL_INVALID_OPERATION:
|
||||
fprintf(stderr, " (GL_INVALID_OPERATION)\n");
|
||||
break;
|
||||
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION:
|
||||
fprintf(stderr, " (GL_INVALID_FRAMEBUFFER_OPERATION)\n");
|
||||
break;
|
||||
|
||||
case GL_OUT_OF_MEMORY:
|
||||
fprintf(stderr, " (GL_OUT_OF_MEMORY)\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
32
client/renderers/EGL/dynprocs.c
Normal file
32
client/renderers/EGL/dynprocs.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
|
||||
https://looking-glass.hostfission.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "dynprocs.h"
|
||||
|
||||
struct EGLDynProcs g_dynprocs = {0};
|
||||
|
||||
void egl_dynProcsInit(void)
|
||||
{
|
||||
g_dynprocs.eglGetPlatformDisplay = (eglGetPlatformDisplayEXT_t)
|
||||
eglGetProcAddress("eglGetPlatformDisplay");
|
||||
g_dynprocs.eglGetPlatformDisplayEXT = (eglGetPlatformDisplayEXT_t)
|
||||
eglGetProcAddress("eglGetPlatformDisplayEXT");
|
||||
g_dynprocs.glEGLImageTargetTexture2DOES = (glEGLImageTargetTexture2DOES_t)
|
||||
eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
};
|
||||
37
client/renderers/EGL/dynprocs.h
Normal file
37
client/renderers/EGL/dynprocs.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
|
||||
https://looking-glass.hostfission.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <SDL2/SDL_egl.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
typedef EGLDisplay (*eglGetPlatformDisplayEXT_t)(EGLenum platform,
|
||||
void *native_display, const EGLint *attrib_list);
|
||||
typedef void (*glEGLImageTargetTexture2DOES_t)(GLenum target,
|
||||
GLeglImageOES image);
|
||||
|
||||
struct EGLDynProcs
|
||||
{
|
||||
eglGetPlatformDisplayEXT_t eglGetPlatformDisplay;
|
||||
eglGetPlatformDisplayEXT_t eglGetPlatformDisplayEXT;
|
||||
glEGLImageTargetTexture2DOES_t glEGLImageTargetTexture2DOES;
|
||||
};
|
||||
|
||||
extern struct EGLDynProcs g_dynprocs;
|
||||
|
||||
void egl_dynProcsInit(void);
|
||||
@@ -37,6 +37,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <assert.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "dynprocs.h"
|
||||
#include "model.h"
|
||||
#include "shader.h"
|
||||
#include "desktop.h"
|
||||
@@ -102,17 +103,6 @@ struct Inst
|
||||
LG_FontObj fontObj;
|
||||
};
|
||||
|
||||
static bool egl_vsync_option_validator(struct Option * opt, const char ** error)
|
||||
{
|
||||
if (opt->value.x_bool && getenv("WAYLAND_DISPLAY"))
|
||||
{
|
||||
DEBUG_WARN("Cannot disable vsync on Wayland, forcing egl:vsync=off");
|
||||
opt->value.x_bool = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct Option egl_options[] =
|
||||
{
|
||||
{
|
||||
@@ -121,7 +111,6 @@ static struct Option egl_options[] =
|
||||
.description = "Enable vsync",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false,
|
||||
.validator = &egl_vsync_option_validator
|
||||
},
|
||||
{
|
||||
.module = "egl",
|
||||
@@ -241,6 +230,16 @@ void egl_deinitialize(void * opaque)
|
||||
|
||||
LG_LOCK_FREE(this->lock);
|
||||
|
||||
eglMakeCurrent(this->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
if (this->frameContext)
|
||||
eglDestroyContext(this->display, this->frameContext);
|
||||
|
||||
if (this->context)
|
||||
eglDestroyContext(this->display, this->context);
|
||||
|
||||
eglTerminate(this->display);
|
||||
|
||||
free(this);
|
||||
}
|
||||
|
||||
@@ -495,43 +494,28 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useNative = false;
|
||||
{
|
||||
const char *client_exts = eglQueryString(NULL, EGL_EXTENSIONS);
|
||||
if (strstr(client_exts, "EGL_KHR_platform_base") != NULL)
|
||||
useNative = true;
|
||||
}
|
||||
egl_dynProcsInit();
|
||||
|
||||
DEBUG_INFO("use native: %s", useNative ? "true" : "false");
|
||||
EGLNativeDisplayType native;
|
||||
EGLenum platform;
|
||||
|
||||
switch(wminfo.subsystem)
|
||||
{
|
||||
case SDL_SYSWM_X11:
|
||||
{
|
||||
if (!useNative)
|
||||
this->display = eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR, wminfo.info.x11.display, NULL);
|
||||
else
|
||||
{
|
||||
EGLNativeDisplayType native = (EGLNativeDisplayType)wminfo.info.x11.display;
|
||||
this->display = eglGetDisplay(native);
|
||||
}
|
||||
native = (EGLNativeDisplayType)wminfo.info.x11.display;
|
||||
platform = EGL_PLATFORM_X11_KHR;
|
||||
this->nativeWind = (EGLNativeWindowType)wminfo.info.x11.window;
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(SDL_VIDEO_DRIVER_WAYLAND)
|
||||
case SDL_SYSWM_WAYLAND:
|
||||
{
|
||||
int width, height;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
if (!useNative)
|
||||
this->display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, wminfo.info.wl.display, NULL);
|
||||
else
|
||||
{
|
||||
EGLNativeDisplayType native = (EGLNativeDisplayType)wminfo.info.wl.display;
|
||||
this->display = eglGetDisplay(native);
|
||||
}
|
||||
this->nativeWind = (EGLNativeWindowType)wl_egl_window_create(wminfo.info.wl.surface, width, height);
|
||||
native = (EGLNativeDisplayType)wminfo.info.wl.display;
|
||||
platform = EGL_PLATFORM_WAYLAND_KHR;
|
||||
this->nativeWind = (EGLNativeWindowType)wl_egl_window_create(
|
||||
wminfo.info.wl.surface, width, height);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -541,6 +525,25 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *early_exts = eglQueryString(NULL, EGL_EXTENSIONS);
|
||||
if (strstr(early_exts, "EGL_KHR_platform_base") != NULL &&
|
||||
g_dynprocs.eglGetPlatformDisplay)
|
||||
{
|
||||
DEBUG_INFO("Using eglGetPlatformDisplay");
|
||||
this->display = g_dynprocs.eglGetPlatformDisplay(platform, native, NULL);
|
||||
}
|
||||
else if (strstr(early_exts, "EGL_EXT_platform_base") != NULL &&
|
||||
g_dynprocs.eglGetPlatformDisplayEXT)
|
||||
{
|
||||
DEBUG_INFO("Using eglGetPlatformDisplayEXT");
|
||||
this->display = g_dynprocs.eglGetPlatformDisplayEXT(platform, native, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO("Using eglGetDisplay");
|
||||
this->display = eglGetDisplay(native);
|
||||
}
|
||||
|
||||
if (this->display == EGL_NO_DISPLAY)
|
||||
{
|
||||
DEBUG_ERROR("eglGetDisplay failed");
|
||||
@@ -636,20 +639,27 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
|
||||
DEBUG_INFO("EGL APIs : %s", eglQueryString(this->display, EGL_CLIENT_APIS));
|
||||
DEBUG_INFO("Extensions: %s", client_exts);
|
||||
|
||||
if (strstr(client_exts, "EGL_EXT_image_dma_buf_import") != NULL)
|
||||
if (g_dynprocs.glEGLImageTargetTexture2DOES)
|
||||
{
|
||||
/*
|
||||
* As of version 455.45.01 NVidia started advertising support for this
|
||||
* feature, however even on the latest version 460.27.04 this is still
|
||||
* broken and does not work, until this is fixed and we have way to detect
|
||||
* this early just disable dma for all NVIDIA devices.
|
||||
*
|
||||
* ref: https://forums.developer.nvidia.com/t/egl-ext-image-dma-buf-import-broken-egl-bad-alloc-with-tons-of-free-ram/165552
|
||||
*/
|
||||
if (strstr(vendor, "NVIDIA") != NULL)
|
||||
DEBUG_WARN("NVIDIA driver detected, ignoring broken DMA support");
|
||||
else
|
||||
this->dmaSupport = true;
|
||||
if (strstr(client_exts, "EGL_EXT_image_dma_buf_import") != NULL)
|
||||
{
|
||||
/*
|
||||
* As of version 455.45.01 NVidia started advertising support for this
|
||||
* feature, however even on the latest version 460.27.04 this is still
|
||||
* broken and does not work, until this is fixed and we have way to detect
|
||||
* this early just disable dma for all NVIDIA devices.
|
||||
*
|
||||
* ref: https://forums.developer.nvidia.com/t/egl-ext-image-dma-buf-import-broken-egl-bad-alloc-with-tons-of-free-ram/165552
|
||||
*/
|
||||
if (strstr(vendor, "NVIDIA") != NULL)
|
||||
DEBUG_WARN("NVIDIA driver detected, ignoring broken DMA support");
|
||||
else
|
||||
this->dmaSupport = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO("glEGLImageTargetTexture2DOES unavilable, DMA support disabled");
|
||||
}
|
||||
|
||||
eglSwapInterval(this->display, this->opt.vsync ? 1 : 0);
|
||||
|
||||
45
client/renderers/EGL/egldebug.c
Normal file
45
client/renderers/EGL/egldebug.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
|
||||
https://looking-glass.hostfission.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 2 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "egldebug.h"
|
||||
#include <SDL2/SDL_egl.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
const char * egl_getErrorStr(void)
|
||||
{
|
||||
switch (eglGetError())
|
||||
{
|
||||
case EGL_SUCCESS : return "EGL_SUCCESS";
|
||||
case EGL_NOT_INITIALIZED : return "EGL_NOT_INITIALIZED";
|
||||
case EGL_BAD_ACCESS : return "EGL_BAD_ACCESS";
|
||||
case EGL_BAD_ALLOC : return "EGL_BAD_ALLOC";
|
||||
case EGL_BAD_ATTRIBUTE : return "EGL_BAD_ATTRIBUTE";
|
||||
case EGL_BAD_CONTEXT : return "EGL_BAD_CONTEXT";
|
||||
case EGL_BAD_CONFIG : return "EGL_BAD_CONFIG";
|
||||
case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
|
||||
case EGL_BAD_DISPLAY : return "EGL_BAD_DISPLAY";
|
||||
case EGL_BAD_SURFACE : return "EGL_BAD_SURFACE";
|
||||
case EGL_BAD_MATCH : return "EGL_BAD_MATCH";
|
||||
case EGL_BAD_PARAMETER : return "EGL_BAD_PARAMETER";
|
||||
case EGL_BAD_NATIVE_PIXMAP : return "EGL_BAD_NATIVE_PIXMAP";
|
||||
case EGL_BAD_NATIVE_WINDOW : return "EGL_BAD_NATIVE_WINDOW";
|
||||
case EGL_CONTEXT_LOST : return "EGL_CONTEXT_LOST";
|
||||
default : return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Looking Glass - KVM FrameRelay (KVMFR) Client
|
||||
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
||||
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
|
||||
https://looking-glass.hostfission.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -17,11 +17,13 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/debug.h>
|
||||
#include "common/debug.h"
|
||||
|
||||
#define EGL_DEBUG_PRINT(type, fmt, ...) do {egl_debug_printf(type " %20s:%-4u | %-30s | " fmt, STRIPPATH(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__);} while (0)
|
||||
#define EGL_ERROR(fmt, ...) EGL_DEBUG_PRINT("[E]", fmt, ##__VA_ARGS__)
|
||||
const char * egl_getErrorStr(void);
|
||||
|
||||
void egl_debug_printf(char * format, ...);
|
||||
#define DEBUG_EGL_WARN(fmt, ...) \
|
||||
DEBUG_WARN(fmt " (%s)", ##__VA_ARGS__, egl_getErrorStr())
|
||||
|
||||
#define DEBUG_EGL_ERROR(fmt, ...) \
|
||||
DEBUG_ERROR(fmt " (%s)", ##__VA_ARGS__, egl_getErrorStr())
|
||||
@@ -154,8 +154,12 @@ void egl_splash_free(EGL_Splash ** splash)
|
||||
if (!*splash)
|
||||
return;
|
||||
|
||||
egl_model_free(&(*splash)->bg );
|
||||
egl_model_free(&(*splash)->logo);
|
||||
|
||||
egl_shader_free(&(*splash)->bgShader );
|
||||
egl_shader_free(&(*splash)->logoShader);
|
||||
|
||||
free(*splash);
|
||||
*splash = NULL;
|
||||
}
|
||||
@@ -174,4 +178,4 @@ void egl_splash_render(EGL_Splash * splash, float alpha, float scaleY)
|
||||
egl_model_render(splash->logo);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "texture.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/framebuffer.h"
|
||||
#include "debug.h"
|
||||
#include "dynprocs.h"
|
||||
#include "utils.h"
|
||||
#include "egldebug.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -141,7 +142,8 @@ static bool egl_texture_map(EGL_Texture * texture, uint8_t i)
|
||||
|
||||
if (!texture->buf[i].map)
|
||||
{
|
||||
EGL_ERROR("glMapBufferRange failed for %d of %lu bytes", i, texture->pboBufferSize);
|
||||
DEBUG_EGL_ERROR("glMapBufferRange failed for %d of %lu bytes", i,
|
||||
texture->pboBufferSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -386,13 +388,13 @@ bool egl_texture_update_from_dma(EGL_Texture * texture, const FrameBuffer * fram
|
||||
|
||||
if (image == EGL_NO_IMAGE)
|
||||
{
|
||||
DEBUG_ERROR("failed to create ELGImage for DMA transfer");
|
||||
DEBUG_EGL_ERROR("Failed to create ELGImage for DMA transfer");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* bind the texture and initiate the transfer */
|
||||
glBindTexture(GL_TEXTURE_2D, texture->tex);
|
||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
|
||||
g_dynprocs.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
|
||||
|
||||
/* wait for completion */
|
||||
framebuffer_wait(frame, texture->height * texture->stride);
|
||||
@@ -480,7 +482,7 @@ enum EGL_TexStatus egl_texture_bind(EGL_Texture * texture)
|
||||
case GL_INVALID_VALUE:
|
||||
glDeleteSync(texture->buf[b].sync);
|
||||
texture->buf[b].sync = 0;
|
||||
EGL_ERROR("glClientWaitSync failed");
|
||||
DEBUG_EGL_ERROR("glClientWaitSync failed");
|
||||
return EGL_TEX_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ project(renderer_Opengl LANGUAGES C)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(RENDERER_OPENGL_PKGCONFIG REQUIRED
|
||||
gl
|
||||
glu
|
||||
)
|
||||
|
||||
add_library(renderer_OpenGL STATIC
|
||||
|
||||
@@ -27,7 +27,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
@@ -48,17 +47,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#define FADE_TIME 1000000
|
||||
|
||||
static bool opengl_vsync_option_validator(struct Option * opt, const char ** error)
|
||||
{
|
||||
if (opt->value.x_bool && getenv("WAYLAND_DISPLAY"))
|
||||
{
|
||||
DEBUG_WARN("Cannot disable vsync on Wayland, forcing opengl:vsync=off");
|
||||
opt->value.x_bool = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct Option opengl_options[] =
|
||||
{
|
||||
{
|
||||
@@ -74,7 +62,6 @@ static struct Option opengl_options[] =
|
||||
.description = "Enable vsync",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false,
|
||||
.validator = &opengl_vsync_option_validator
|
||||
},
|
||||
{
|
||||
.module = "opengl",
|
||||
@@ -331,7 +318,7 @@ void opengl_on_resize(void * opaque, const int width, const int height,
|
||||
glViewport(0, 0, this->window.x, this->window.y);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, this->window.x, this->window.y, 0);
|
||||
glOrtho(0, this->window.x, this->window.y, 0, -1, 1);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
@@ -854,7 +841,40 @@ static bool _check_gl_error(unsigned int line, const char * name)
|
||||
if (error == GL_NO_ERROR)
|
||||
return false;
|
||||
|
||||
const GLubyte * errStr = gluErrorString(error);
|
||||
const char * errStr;
|
||||
switch (error)
|
||||
{
|
||||
case GL_INVALID_ENUM:
|
||||
errStr = "GL_INVALID_ENUM";
|
||||
break;
|
||||
|
||||
case GL_INVALID_VALUE:
|
||||
errStr = "GL_INVALID_VALUE";
|
||||
break;
|
||||
|
||||
case GL_INVALID_OPERATION:
|
||||
errStr = "GL_INVALID_OPERATION";
|
||||
break;
|
||||
|
||||
case GL_STACK_OVERFLOW:
|
||||
errStr = "GL_STACK_OVERFLOW";
|
||||
break;
|
||||
|
||||
case GL_STACK_UNDERFLOW:
|
||||
errStr = "GL_STACK_UNDERFLOW";
|
||||
break;
|
||||
|
||||
case GL_OUT_OF_MEMORY:
|
||||
errStr = "GL_OUT_OF_MEMORY";
|
||||
break;
|
||||
|
||||
case GL_TABLE_TOO_LARGE:
|
||||
errStr = "GL_TABLE_TOO_LARGE";
|
||||
break;
|
||||
|
||||
default:
|
||||
errStr = "unknown error";
|
||||
}
|
||||
DEBUG_ERROR("%d: %s = %d (%s)", line, name, error, errStr);
|
||||
return true;
|
||||
}
|
||||
@@ -1282,7 +1302,7 @@ static bool draw_frame(struct Inst * this)
|
||||
break;
|
||||
|
||||
case GL_WAIT_FAILED:
|
||||
DEBUG_ERROR("Wait failed %s", gluErrorString(glGetError()));
|
||||
DEBUG_ERROR("Wait failed %d", glGetError());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,16 +152,11 @@ void app_handleFocusEvent(bool focused)
|
||||
if (!app_inputEnabled())
|
||||
return;
|
||||
|
||||
if (params.grabKeyboardOnFocus)
|
||||
{
|
||||
if (focused)
|
||||
g_state.ds->grabKeyboard();
|
||||
else
|
||||
g_state.ds->ungrabKeyboard();
|
||||
}
|
||||
|
||||
if (!focused)
|
||||
{
|
||||
setGrabQuiet(false);
|
||||
setCursorInView(false);
|
||||
}
|
||||
|
||||
g_cursor.realign = true;
|
||||
g_state.ds->realignPointer();
|
||||
@@ -506,7 +501,7 @@ static int cursorThread(void * unused)
|
||||
g_cursor.guest.y
|
||||
);
|
||||
|
||||
if (params.mouseRedraw)
|
||||
if (params.mouseRedraw && g_cursor.guest.visible)
|
||||
lgSignalEvent(e_frame);
|
||||
}
|
||||
|
||||
@@ -1013,6 +1008,9 @@ static void setCursorInView(bool enable)
|
||||
|
||||
if (warpSupport && !params.captureInputOnly)
|
||||
g_state.ds->grabPointer();
|
||||
|
||||
if (params.grabKeyboardOnFocus)
|
||||
g_state.ds->grabKeyboard();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1022,7 +1020,7 @@ static void setCursorInView(bool enable)
|
||||
if (warpSupport)
|
||||
g_state.ds->ungrabPointer();
|
||||
|
||||
setGrabQuiet(false);
|
||||
g_state.ds->ungrabKeyboard();
|
||||
}
|
||||
|
||||
g_cursor.warpState = WARP_STATE_ON;
|
||||
@@ -1452,6 +1450,9 @@ void app_handleMouseBasic()
|
||||
int x = (int) round((px - local.x) / g_cursor.dpiScale);
|
||||
int y = (int) round((py - local.y) / g_cursor.dpiScale);
|
||||
|
||||
if (!x && !y)
|
||||
return;
|
||||
|
||||
g_cursor.guest.x += x;
|
||||
g_cursor.guest.y += y;
|
||||
|
||||
@@ -1562,8 +1563,7 @@ static void setGrabQuiet(bool enable)
|
||||
{
|
||||
if (params.grabKeyboard)
|
||||
{
|
||||
if (!g_state.focused || !params.grabKeyboardOnFocus ||
|
||||
params.captureInputOnly)
|
||||
if (!params.grabKeyboardOnFocus || !g_state.focused || params.captureInputOnly)
|
||||
g_state.ds->ungrabKeyboard();
|
||||
}
|
||||
|
||||
@@ -1609,14 +1609,23 @@ int eventFilter(void * userdata, SDL_Event * event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void int_handler(int signal)
|
||||
void int_handler(int sig)
|
||||
{
|
||||
switch(signal)
|
||||
switch(sig)
|
||||
{
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
DEBUG_INFO("Caught signal, shutting down...");
|
||||
g_state.state = APP_STATE_SHUTDOWN;
|
||||
if (g_state.state != APP_STATE_SHUTDOWN)
|
||||
{
|
||||
DEBUG_INFO("Caught signal, shutting down...");
|
||||
g_state.state = APP_STATE_SHUTDOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_INFO("Caught second signal, force quitting...");
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2037,6 +2046,8 @@ static int lg_run(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
lgInit();
|
||||
|
||||
// start the renderThread so we don't just display junk
|
||||
if (!lgCreateThread("renderThread", renderThread, NULL, &t_render))
|
||||
{
|
||||
@@ -2079,8 +2090,6 @@ static int lg_run(void)
|
||||
KVMFR *udata;
|
||||
int waitCount = 0;
|
||||
|
||||
lgInit();
|
||||
|
||||
restart:
|
||||
while(g_state.state == APP_STATE_RUNNING)
|
||||
{
|
||||
@@ -2104,7 +2113,8 @@ restart:
|
||||
{
|
||||
DEBUG_BREAK();
|
||||
DEBUG_INFO("Please check the host application is running and is the correct version");
|
||||
DEBUG_INFO("Check the host log in your guest at %%TEMP%%\\looking-glass-host.txt");
|
||||
DEBUG_INFO("Check the host log in your guest at: "
|
||||
"%%ProgramData%%\\Looking Glass (host)\\looking-glass-host.txt");
|
||||
DEBUG_INFO("Continuing to wait...");
|
||||
}
|
||||
|
||||
|
||||
@@ -223,6 +223,12 @@ void option_free(void)
|
||||
state.options = NULL;
|
||||
state.oCount = 0;
|
||||
|
||||
for(int g = 0; g < state.gCount; ++g)
|
||||
{
|
||||
struct OptionGroup * group = &state.groups[g];
|
||||
if (group->options)
|
||||
free(group->options);
|
||||
}
|
||||
free(state.groups);
|
||||
state.groups = NULL;
|
||||
state.gCount = 0;
|
||||
|
||||
@@ -20,3 +20,7 @@ target_link_libraries(lg_common_platform_code
|
||||
lg_common
|
||||
setupapi
|
||||
)
|
||||
|
||||
if (ENABLE_BACKTRACE)
|
||||
target_link_libraries(lg_common_platform_code dbghelp)
|
||||
endif()
|
||||
|
||||
@@ -18,9 +18,142 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "common/crash.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/version.h"
|
||||
|
||||
#ifdef ENABLE_BACKTRACE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
static const char * exception_name(DWORD code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
return "ACCESS_VIOLATION";
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
return "ARRAY_BOUNDS_EXCEEDED";
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
return "BREAKPOINT";
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
return "DATATYPE_MISALIGNMENT";
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
return "FLT_DENORMAL_OPERAND";
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
return "FLT_DIVIDE_BY_ZERO";
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
return "FLT_INEXACT_RESULT";
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
return "FLT_INVALID_OPERATION";
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
return "FLT_OVERFLOW";
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
return "FLT_STACK_CHECK";
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
return "FLT_UNDERFLOW";
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
return "ILLEGAL_INSTRUCTION";
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
return "IN_PAGE_ERROR";
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
return "INT_DIVIDE_BY_ZERO";
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
return "INT_OVERFLOW";
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
return "INVALID_DISPOSITION";
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
return "NONCONTINUABLE_EXCEPTION";
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
return "PRIV_INSTRUCTION";
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
return "SINGLE_STEP";
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
return "STACK_OVERFLOW";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static LONG CALLBACK exception_filter(EXCEPTION_POINTERS * exc)
|
||||
{
|
||||
PEXCEPTION_RECORD excInfo = exc->ExceptionRecord;
|
||||
CONTEXT context;
|
||||
memcpy(&context, exc->ContextRecord, sizeof context);
|
||||
|
||||
DEBUG_ERROR("==== FATAL CRASH (%s) ====", BUILD_VERSION);
|
||||
DEBUG_ERROR("exception 0x%08lx (%s), address is %p", excInfo->ExceptionCode,
|
||||
exception_name(excInfo->ExceptionCode), excInfo->ExceptionAddress);
|
||||
|
||||
if (!SymInitialize(GetCurrentProcess(), NULL, TRUE))
|
||||
{
|
||||
DEBUG_ERROR("Failed to SymInitialize: 0x%08lx, could not generate stack trace", GetLastError());
|
||||
goto fail;
|
||||
}
|
||||
SymSetOptions(SYMOPT_LOAD_LINES);
|
||||
|
||||
STACKFRAME64 frame = { 0 };
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rbp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Rsp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
HANDLE hThread = GetCurrentThread();
|
||||
|
||||
for (int i = 1; StackWalk64(IMAGE_FILE_MACHINE_AMD64, hProcess, hThread, &frame, &context, NULL,
|
||||
SymFunctionTableAccess64, SymGetModuleBase64, NULL); ++i)
|
||||
{
|
||||
DWORD64 moduleBase = SymGetModuleBase64(hProcess, frame.AddrPC.Offset);
|
||||
char moduleName[MAX_PATH];
|
||||
|
||||
if (moduleBase && GetModuleFileNameA((HMODULE) moduleBase, moduleName, MAX_PATH))
|
||||
{
|
||||
DWORD64 disp;
|
||||
|
||||
char symbolBuf[sizeof(SYMBOL_INFO) + 255];
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO) symbolBuf;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = 256;
|
||||
|
||||
if (SymFromAddr(hProcess, frame.AddrPC.Offset, &disp, symbol))
|
||||
{
|
||||
IMAGEHLP_LINE line = { sizeof(IMAGEHLP_LINE), 0 };
|
||||
DWORD lineDisp;
|
||||
|
||||
if (SymGetLineFromAddr64(hProcess, frame.AddrPC.Offset, &lineDisp, &line))
|
||||
DEBUG_ERROR("[trace]: %2d: %s:%s+0x%" PRIx64 " (%s:%ld+0x%lx)", i, moduleName, symbol->Name, disp,
|
||||
line.FileName, line.LineNumber, lineDisp);
|
||||
else
|
||||
DEBUG_ERROR("[trace]: %2d: %s:%s+0x%" PRIx64, i, moduleName, symbol->Name, disp);
|
||||
}
|
||||
else
|
||||
DEBUG_ERROR("[trace]: %2d: %s+0x%08" PRIx64, i, moduleName, frame.AddrPC.Offset - moduleBase);
|
||||
}
|
||||
else
|
||||
DEBUG_ERROR("[trace]: %2d: 0x%016" PRIx64, i, frame.AddrPC.Offset);
|
||||
}
|
||||
|
||||
SymCleanup(hProcess);
|
||||
|
||||
fail:
|
||||
fflush(stderr);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
bool installCrashHandler(const char * exe)
|
||||
{
|
||||
//TODO
|
||||
SetUnhandledExceptionFilter(exception_filter);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
bool installCrashHandler(const char * exe)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,12 +6,17 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
include(CheckCCompilerFlag)
|
||||
include(FeatureSummary)
|
||||
|
||||
option(OPTIMIZE_FOR_NATIVE "Build with -march=native" ON)
|
||||
option(OPTIMIZE_FOR_NATIVE "Build with -march=native" OFF)
|
||||
if(OPTIMIZE_FOR_NATIVE)
|
||||
CHECK_C_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
if(COMPILER_SUPPORTS_MARCH_NATIVE)
|
||||
add_compile_options("-march=native")
|
||||
endif()
|
||||
else()
|
||||
CHECK_C_COMPILER_FLAG("-march=nehalem" COMPILER_SUPPORTS_MARCH_NEHALEM)
|
||||
if(COMPILER_SUPPORTS_MARCH_NEHALEM)
|
||||
add_compile_options("-march=nehalem")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(ENABLE_BACKTRACE "Enable backtrace support on crash" ON)
|
||||
|
||||
@@ -54,16 +54,19 @@ The resulting installer will be at
|
||||
|
||||
## Where is the log?
|
||||
|
||||
It is in your user's temp directory:
|
||||
The log file for the host application is located at:
|
||||
|
||||
%TEMP%\looking-glass-host.txt
|
||||
%ProgramData%\Looking Glass (host)\looking-glass-host.txt
|
||||
|
||||
Or if running as a system service it will be located in:
|
||||
You can also find out where the file is by right clicking on the tray icon and
|
||||
selecting "Log File Location".
|
||||
|
||||
C:\Windows\Temp\looking-glass-host.txt
|
||||
The log file for the looking glass service is located at:
|
||||
|
||||
You can find out where the file is by right clicking on the tray icon and
|
||||
selecting "Log File Location"
|
||||
%ProgramData%\Looking Glass (host)\looking-glass-host-service.txt
|
||||
|
||||
This is useful for troubleshooting errors related to the host application not
|
||||
starting.
|
||||
|
||||
### High priority capture using DXGI and Secure Desktop (UAC) capture support
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ target_link_libraries(platform_Windows
|
||||
userenv
|
||||
wtsapi32
|
||||
psapi
|
||||
shlwapi
|
||||
)
|
||||
|
||||
target_include_directories(platform_Windows
|
||||
|
||||
@@ -743,7 +743,7 @@ static CaptureResult dxgi_capture(void)
|
||||
assert(this);
|
||||
assert(this->initialized);
|
||||
|
||||
Texture * tex;
|
||||
Texture * tex = NULL;
|
||||
CaptureResult result;
|
||||
HRESULT status;
|
||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||
|
||||
@@ -60,12 +60,16 @@ struct iface
|
||||
LGEvent * cursorEvents[2];
|
||||
|
||||
int mouseX, mouseY, mouseHotX, mouseHotY;
|
||||
bool mouseVisible;
|
||||
bool mouseVisible, hasMousePosition;
|
||||
|
||||
bool mouseHookCreated;
|
||||
bool forceCompositionCreated;
|
||||
};
|
||||
|
||||
static struct iface * this = NULL;
|
||||
|
||||
static void nvfbc_free();
|
||||
static bool nvfbc_deinit(void);
|
||||
static void nvfbc_free(void);
|
||||
static int pointerThread(void * unused);
|
||||
|
||||
static void getDesktopSize(unsigned int * width, unsigned int * height, unsigned int * dpi)
|
||||
@@ -84,8 +88,9 @@ static void getDesktopSize(unsigned int * width, unsigned int * height, unsigned
|
||||
|
||||
static void on_mouseMove(int x, int y)
|
||||
{
|
||||
this->mouseX = x;
|
||||
this->mouseY = y;
|
||||
this->hasMousePosition = true;
|
||||
this->mouseX = x;
|
||||
this->mouseY = y;
|
||||
lgSignalEvent(this->cursorEvents[0]);
|
||||
}
|
||||
|
||||
@@ -118,36 +123,7 @@ static bool nvfbc_create(
|
||||
if (!NvFBCInit())
|
||||
return false;
|
||||
|
||||
int bufferLen = GetEnvironmentVariable("NVFBC_PRIV_DATA", NULL, 0);
|
||||
uint8_t * privData = NULL;
|
||||
int privDataLen = 0;
|
||||
|
||||
if(bufferLen)
|
||||
{
|
||||
char * buffer = malloc(bufferLen);
|
||||
GetEnvironmentVariable("NVFBC_PRIV_DATA", buffer, bufferLen);
|
||||
|
||||
privDataLen = (bufferLen - 1) / 2;
|
||||
privData = (uint8_t *)malloc(privDataLen);
|
||||
char hex[3] = {0};
|
||||
for(int i = 0; i < privDataLen; ++i)
|
||||
{
|
||||
memcpy(hex, &buffer[i*2], 2);
|
||||
privData[i] = (uint8_t)strtoul(hex, NULL, 16);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
this = (struct iface *)calloc(sizeof(struct iface), 1);
|
||||
if (!NvFBCToSysCreate(privData, privDataLen, &this->nvfbc, &this->maxWidth, &this->maxHeight))
|
||||
{
|
||||
free(privData);
|
||||
nvfbc_free();
|
||||
return false;
|
||||
}
|
||||
free(privData);
|
||||
|
||||
this->frameEvent = lgCreateEvent(true, 17);
|
||||
if (!this->frameEvent)
|
||||
{
|
||||
@@ -166,6 +142,35 @@ static bool nvfbc_create(
|
||||
static bool nvfbc_init(void)
|
||||
{
|
||||
this->stop = false;
|
||||
|
||||
int bufferLen = GetEnvironmentVariable("NVFBC_PRIV_DATA", NULL, 0);
|
||||
uint8_t * privData = NULL;
|
||||
int privDataLen = 0;
|
||||
|
||||
if (bufferLen)
|
||||
{
|
||||
char * buffer = malloc(bufferLen);
|
||||
GetEnvironmentVariable("NVFBC_PRIV_DATA", buffer, bufferLen);
|
||||
|
||||
privDataLen = (bufferLen - 1) / 2;
|
||||
privData = (uint8_t *)malloc(privDataLen);
|
||||
char hex[3] = {0};
|
||||
for(int i = 0; i < privDataLen; ++i)
|
||||
{
|
||||
memcpy(hex, &buffer[i*2], 2);
|
||||
privData[i] = (uint8_t)strtoul(hex, NULL, 16);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
if (!NvFBCToSysCreate(privData, privDataLen, &this->nvfbc, &this->maxWidth, &this->maxHeight))
|
||||
{
|
||||
free(privData);
|
||||
return false;
|
||||
}
|
||||
free(privData);
|
||||
|
||||
getDesktopSize(&this->width, &this->height, &this->dpi);
|
||||
lgResetEvent(this->frameEvent);
|
||||
|
||||
@@ -186,12 +191,21 @@ static bool nvfbc_init(void)
|
||||
}
|
||||
|
||||
this->cursorEvents[0] = lgCreateEvent(true, 10);
|
||||
mouseHook_install(on_mouseMove);
|
||||
|
||||
if (this->seperateCursor)
|
||||
this->cursorEvents[1] = lgWrapEvent(event);
|
||||
|
||||
dwmForceComposition();
|
||||
if (!this->mouseHookCreated)
|
||||
{
|
||||
mouseHook_install(on_mouseMove);
|
||||
this->mouseHookCreated = true;
|
||||
}
|
||||
|
||||
if (!this->forceCompositionCreated)
|
||||
{
|
||||
dwmForceComposition();
|
||||
this->forceCompositionCreated = true;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Cursor mode : %s", this->seperateCursor ? "decoupled" : "integrated");
|
||||
|
||||
@@ -200,6 +214,7 @@ static bool nvfbc_init(void)
|
||||
if (!lgCreateThread("NvFBCPointer", pointerThread, NULL, &this->pointerThread))
|
||||
{
|
||||
DEBUG_ERROR("Failed to create the NvFBCPointer thread");
|
||||
nvfbc_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -223,25 +238,32 @@ static void nvfbc_stop(void)
|
||||
|
||||
static bool nvfbc_deinit(void)
|
||||
{
|
||||
mouseHook_remove();
|
||||
dwmUnforceComposition();
|
||||
|
||||
if (this->cursorEvents[0])
|
||||
{
|
||||
lgFreeEvent(this->cursorEvents[0]);
|
||||
this->cursorEvents[0] = NULL;
|
||||
}
|
||||
|
||||
if (this->nvfbc)
|
||||
{
|
||||
NvFBCToSysRelease(&this->nvfbc);
|
||||
this->nvfbc = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nvfbc_free(void)
|
||||
{
|
||||
NvFBCToSysRelease(&this->nvfbc);
|
||||
|
||||
if (this->frameEvent)
|
||||
lgFreeEvent(this->frameEvent);
|
||||
|
||||
if (this->mouseHookCreated)
|
||||
mouseHook_remove();
|
||||
|
||||
if (this->forceCompositionCreated)
|
||||
dwmUnforceComposition();
|
||||
|
||||
free(this);
|
||||
this = NULL;
|
||||
NvFBCFree();
|
||||
@@ -350,6 +372,8 @@ static CaptureResult nvfbc_getFrame(FrameBuffer * frame)
|
||||
|
||||
static int pointerThread(void * unused)
|
||||
{
|
||||
lgSignalEvent(this->cursorEvents[1]);
|
||||
|
||||
while(!this->stop)
|
||||
{
|
||||
LGEvent * events[2];
|
||||
@@ -362,6 +386,7 @@ static int pointerThread(void * unused)
|
||||
|
||||
CaptureResult result;
|
||||
CapturePointer pointer = { 0 };
|
||||
bool hotspotUpdated = false;
|
||||
|
||||
if (this->seperateCursor && events[1])
|
||||
{
|
||||
@@ -383,9 +408,10 @@ static int pointerThread(void * unused)
|
||||
this->mouseVisible = pointer.visible;
|
||||
this->mouseHotX = pointer.hx;
|
||||
this->mouseHotY = pointer.hy;
|
||||
hotspotUpdated = true;
|
||||
}
|
||||
|
||||
if (events[0])
|
||||
if (events[0] || (hotspotUpdated && this->hasMousePosition))
|
||||
{
|
||||
pointer.positionUpdate = true;
|
||||
pointer.visible = this->mouseVisible;
|
||||
|
||||
@@ -129,6 +129,7 @@ Section "-Install" Section1
|
||||
|
||||
SetOutPath $INSTDIR
|
||||
File ..\..\looking-glass-host.exe
|
||||
File /nonfatal ..\..\looking-glass-host.pdb
|
||||
File LICENSE.txt
|
||||
WriteUninstaller $INSTDIR\uninstaller.exe
|
||||
|
||||
@@ -171,7 +172,7 @@ Section /o "Desktop Shortcut" Section3
|
||||
StrCpy $option_desktop 1
|
||||
SectionEnd
|
||||
|
||||
Section /o "Start Menu Shortcut" Section4
|
||||
Section "Start Menu Shortcut" Section4
|
||||
StrCpy $option_startMenu 1
|
||||
SectionEnd
|
||||
|
||||
@@ -179,7 +180,10 @@ Section "-Hidden Start Menu" Section5
|
||||
SetShellVarContext all
|
||||
|
||||
${If} $option_startMenu == 1
|
||||
CreateShortCut "$SMPROGRAMS\Looking Glass (host).lnk" $INSTDIR\looking-glass-host.exe
|
||||
CreateDirectory "$APPDATA\Looking Glass (host)"
|
||||
CreateDirectory "$SMPROGRAMS\Looking Glass (host)"
|
||||
CreateShortCut "$SMPROGRAMS\Looking Glass (host)\Looking Glass (host).lnk" $INSTDIR\looking-glass-host.exe
|
||||
CreateShortCut "$SMPROGRAMS\Looking Glass (host)\Looking Glass Logs.lnk" "$APPDATA\Looking Glass (host)"
|
||||
${EndIf}
|
||||
|
||||
${If} $option_desktop == 1
|
||||
|
||||
@@ -56,6 +56,13 @@ static bool switchDesktopAndHook(void)
|
||||
}
|
||||
CloseDesktop(desk);
|
||||
|
||||
POINT position;
|
||||
GetCursorPos(&position);
|
||||
|
||||
mouseHook.x = position.x;
|
||||
mouseHook.y = position.y;
|
||||
mouseHook.callback(position.x, position.y);
|
||||
|
||||
mouseHook.hook = SetWindowsHookEx(WH_MOUSE_LL, mouseHook_hook, NULL, 0);
|
||||
if (!mouseHook.hook)
|
||||
{
|
||||
@@ -84,11 +91,11 @@ static DWORD WINAPI threadProc(LPVOID lParam) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mouseHook.callback = (MouseHookFn)lParam;
|
||||
if (!switchDesktopAndHook())
|
||||
return 0;
|
||||
|
||||
mouseHook.installed = true;
|
||||
mouseHook.callback = (MouseHookFn)lParam;
|
||||
|
||||
HWINEVENTHOOK eventHook = SetWinEventHook(
|
||||
EVENT_SYSTEM_DESKTOPSWITCH, EVENT_SYSTEM_DESKTOPSWITCH, NULL,
|
||||
|
||||
@@ -23,6 +23,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "interface/platform.h"
|
||||
@@ -34,6 +35,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#define ID_MENU_SHOW_LOG 3000
|
||||
#define ID_MENU_EXIT 3001
|
||||
#define LOG_NAME "looking-glass-host.txt"
|
||||
|
||||
struct AppState
|
||||
{
|
||||
@@ -44,6 +46,7 @@ struct AppState
|
||||
char ** argv;
|
||||
|
||||
char executable[MAX_PATH + 1];
|
||||
char systemLogDir[MAX_PATH];
|
||||
HWND messageWnd;
|
||||
NOTIFYICONDATA iconData;
|
||||
UINT trayRestartMsg;
|
||||
@@ -166,6 +169,29 @@ static BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char *getSystemLogDirectory(void)
|
||||
{
|
||||
return app.systemLogDir;
|
||||
}
|
||||
|
||||
static void populateSystemLogDirectory()
|
||||
{
|
||||
char programData[MAX_PATH];
|
||||
if (GetEnvironmentVariableA("ProgramData", programData, sizeof(programData)) &&
|
||||
PathIsDirectoryA(programData))
|
||||
{
|
||||
if (!PathCombineA(app.systemLogDir, programData, "Looking Glass (host)"))
|
||||
goto fail;
|
||||
|
||||
if (!PathIsDirectoryA(app.systemLogDir) && !CreateDirectoryA(app.systemLogDir, NULL))
|
||||
goto fail;
|
||||
|
||||
return;
|
||||
}
|
||||
fail:
|
||||
strcpy(app.systemLogDir, "");
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
// convert the command line to the standard argc and argv
|
||||
@@ -180,6 +206,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
LocalFree(wargv);
|
||||
|
||||
GetModuleFileName(NULL, app.executable, sizeof(app.executable));
|
||||
populateSystemLogDirectory();
|
||||
|
||||
if (HandleService(app.argc, app.argv))
|
||||
return LG_HOST_EXIT_FAILED;
|
||||
|
||||
@@ -201,11 +229,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
int result = 0;
|
||||
app.hInst = hInstance;
|
||||
|
||||
char tempPath[MAX_PATH+1];
|
||||
GetTempPathA(sizeof(tempPath), tempPath);
|
||||
int len = snprintf(NULL, 0, "%slooking-glass-host.txt", tempPath);
|
||||
char * logFilePath = malloc(len + 1);
|
||||
sprintf(logFilePath, "%slooking-glass-host.txt", tempPath);
|
||||
char logFilePath[MAX_PATH];
|
||||
if (!PathCombineA(logFilePath, app.systemLogDir, LOG_NAME))
|
||||
strcpy(logFilePath, LOG_NAME);
|
||||
|
||||
struct Option options[] =
|
||||
{
|
||||
@@ -220,7 +246,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
};
|
||||
|
||||
option_register(options);
|
||||
free(logFilePath);
|
||||
|
||||
// setup a handler for ctrl+c
|
||||
SetConsoleCtrlHandler(CtrlHandler, TRUE);
|
||||
|
||||
@@ -30,4 +30,5 @@ struct MSG_CALL_FUNCTION
|
||||
LPARAM lParam;
|
||||
};
|
||||
|
||||
const char *getSystemLogDirectory(void);
|
||||
LRESULT sendAppMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
@@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include "interface/platform.h"
|
||||
#include "common/ivshmem.h"
|
||||
#include "service.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
@@ -29,6 +30,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#include <time.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
#include <winsvc.h>
|
||||
#include <psapi.h>
|
||||
#include <sddl.h>
|
||||
@@ -37,6 +39,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#define SVCNAME "Looking Glass (host)"
|
||||
#define SVC_ERROR ((DWORD)0xC0020001L)
|
||||
#define LOG_NAME "looking-glass-host-service.txt"
|
||||
|
||||
/*
|
||||
* Windows 10 provides this API via kernel32.dll as well as advapi32.dll and
|
||||
@@ -112,12 +115,11 @@ static bool setupAPI(void)
|
||||
|
||||
static void setupLogging(void)
|
||||
{
|
||||
char tempPath[MAX_PATH+1];
|
||||
GetTempPathA(sizeof(tempPath), tempPath);
|
||||
int len = snprintf(NULL, 0, "%slooking-glass-host-service.txt", tempPath);
|
||||
char * logFilePath = malloc(len + 1);
|
||||
sprintf(logFilePath, "%slooking-glass-host-service.txt", tempPath);
|
||||
char logFilePath[MAX_PATH];
|
||||
if (!PathCombineA(logFilePath, getSystemLogDirectory(), LOG_NAME))
|
||||
strcpy(logFilePath, LOG_NAME);
|
||||
service.logFile = fopen(logFilePath, "a+");
|
||||
setbuf(service.logFile, NULL);
|
||||
doLog("Startup\n");
|
||||
}
|
||||
|
||||
@@ -644,7 +646,7 @@ VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
|
||||
while(1)
|
||||
{
|
||||
ULONGLONG launchTime;
|
||||
ULONGLONG launchTime = 0ULL;
|
||||
|
||||
DWORD interactiveSession = WTSGetActiveConsoleSessionId();
|
||||
if (interactiveSession != 0 && interactiveSession != 0xFFFFFFFF)
|
||||
|
||||
@@ -467,7 +467,7 @@ int app_main(int argc, char * argv[])
|
||||
.magic = KVMFR_MAGIC,
|
||||
.version = KVMFR_VERSION,
|
||||
};
|
||||
strncpy(udata.hostver, BUILD_VERSION, sizeof(udata.hostver));
|
||||
strncpy(udata.hostver, BUILD_VERSION, sizeof(udata.hostver)-1);
|
||||
|
||||
LGMP_STATUS status;
|
||||
if ((status = lgmpHostInit(shmDev.mem, shmDev.size, &app.lgmp,
|
||||
|
||||
Submodule repos/PureSpice updated: cc4a17b330...00961e8f43
Reference in New Issue
Block a user