1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
// Copyright 2015-2022 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
// This file is included by overlay.c for
// Mac-specific overlay initialization.
@implementation NSOpenGLContext (MumbleOverlay)
- (void)overlayFlushBuffer {
ods("[NSOpenGLContext flushBuffer] %p %p", self, [self CGLContextObj]);
Context *c = contexts;
while (c) {
if (c->nsctx == self && c->cglctx == [self CGLContextObj])
break;
c = c->next;
}
if (!c) {
ods("Current context is: %p", self);
c = malloc(sizeof(Context));
if (!c) {
ods("malloc failure");
return;
}
c->next = contexts;
c->nsctx = (NSOpenGLContext *) self;
c->cglctx = (CGLContextObj)[self CGLContextObj];
contexts = c;
newContext(c);
}
NSView *v = [c->nsctx view];
int width = 0, height = 0;
if (v) {
NSRect r = [v bounds];
width = (int) r.size.width;
height = (int) r.size.height;
} else {
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
width = viewport[2];
height = viewport[3];
}
drawContext(c, width, height);
[self overlayFlushBuffer];
}
@end
void CGLFlushDrawableOverride(CGLContextObj ctx) {
ods("CGLFlushDrawableOverride %p", ctx);
Context *c = contexts;
/* Sometimes, we can get a FlushDrawable where the current context is NULL.
* Also, check that the context CGLFlushDrawable was called on is the active context.
* If it isn't, who knows what context we're drawing on?
*
* Maybe we should even use CGLSetCurrentContext() to switch to the context that's being
* flushed?
*/
CGLContextObj current = CGLGetCurrentContext();
if (current == NULL || ctx != current)
goto skip;
while (c) {
if (c->cglctx == ctx) {
/* There is no NSOpenGLContext for this CGLContext, so we should draw. */
if (c->nsctx == NULL)
break;
/* This context is coupled with a NSOpenGLContext, so skip. */
else
goto skip;
}
c = c->next;
}
if (!c) {
ods("Current context is: %p", ctx);
c = malloc(sizeof(Context));
if (!c) {
ods("malloc failure");
return;
}
memset(c, 0, sizeof(Context));
c->next = contexts;
c->cglctx = ctx;
c->nsctx = NULL;
contexts = c;
newContext(c);
}
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
int width = viewport[2];
int height = viewport[3];
/* Are the viewport values crazy? Skip them in that case. */
if (height < 0 || width < 0 || height > 5000 || width > 5000) {
goto skip;
}
drawContext(c, width, height);
skip:
oCGLFlushDrawable(ctx);
}
CGError CGDisplayShowCursorOverride(CGDirectDisplayID display) {
ods("CGDisplayShowCursor()");
return oCGDisplayShowCursor(display);
}
CGError CGDisplayHideCursorOverride(CGDirectDisplayID display) {
ods("CGDisplayHideCursor()");
return oCGDisplayHideCursor(display);
}
__attribute__((constructor)) static void initializeLibrary() {
struct stat buf;
bDebug = (stat("/Library/Application Support/.mumble_overlay_debug", &buf) == 0);
ods("!");
void *nsgl = NULL;
nsgl = dlsym(RTLD_DEFAULT, "NSClassFromString");
/* Check for GL symbol availability */
if (!(AVAIL_ALL_GLSYM)) {
ods("Missing GL symbols. Disabling overlay.");
return;
}
/* NSOpenGL */
if (nsgl) {
ods("Attempting to hook NSOpenGL");
Class c = NSClassFromString(@"NSOpenGLContext");
if (c) {
Method orig = class_getInstanceMethod(c, @selector(flushBuffer));
Method new = class_getInstanceMethod(c, @selector(overlayFlushBuffer));
if (class_addMethod(c, @selector(flushBuffer), method_getImplementation(new), method_getTypeEncoding(new)))
class_replaceMethod(c, @selector(overlayFlushBuffer), method_getImplementation(orig),
method_getTypeEncoding(orig));
else
method_exchangeImplementations(orig, new);
}
}
/* CGL */
if (AVAIL(CGLFlushDrawable)) {
ods("Attempting to hook CGL");
if (mach_override_ptr(dlsym(RTLD_DEFAULT, "CGLFlushDrawable"), CGLFlushDrawableOverride,
(void **) &oCGLFlushDrawable)
!= 0) {
ods("CGLFlushDrawable override failed.");
} else
ods("Up running.");
} else {
ods("Required entry points not available in process. Not hooking up overlay.");
}
if (AVAIL(CGDisplayHideCursor) && AVAIL(CGDisplayShowCursor)) {
if (mach_override_ptr(dlsym(RTLD_DEFAULT, "CGDisplayHideCursor"), CGDisplayHideCursorOverride,
(void **) &oCGDisplayHideCursor)
!= 0) {
ods("CGDisplayHideCursor override failed");
}
if (mach_override_ptr(dlsym(RTLD_DEFAULT, "CGDisplayShowCursor"), CGDisplayShowCursorOverride,
(void **) &oCGDisplayShowCursor)
!= 0) {
ods("CGDisplayShowCursor override failed");
}
ods("Hooked CGDisplayShowCursor and CGDisplayHideCursor");
bCursorAvail = true;
}
}
|