1
/* -- macosxCGS.c -- */
4
* We need to keep this separate from nearly everything else, e.g. rfb.h
5
* and the other stuff, otherwise it does not work properly, mouse drags
8
void macosxCGS_unused(void) {}
10
#if (defined(__MACH__) && defined(__APPLE__))
12
#include <ApplicationServices/ApplicationServices.h>
13
#include <Cocoa/Cocoa.h>
14
#include <Carbon/Carbon.h>
16
extern CGDirectDisplayID displayID;
18
void macosxCGS_get_all_windows(void);
19
int macosxCGS_get_qlook(int);
20
void macosxGCS_set_pasteboard(char *str, int len);
22
typedef CGError CGSError;
23
typedef long CGSWindowCount;
24
typedef void * CGSConnectionID;
25
typedef int CGSWindowID;
26
typedef CGSWindowID* CGSWindowIDList;
27
typedef CGWindowLevel CGSWindowLevel;
28
typedef NSRect CGSRect;
30
extern CGSConnectionID _CGSDefaultConnection ();
32
extern CGSError CGSGetOnScreenWindowList (CGSConnectionID cid,
33
CGSConnectionID owner, CGSWindowCount listCapacity,
34
CGSWindowIDList list, CGSWindowCount *listCount);
36
extern CGSError CGSGetWindowList (CGSConnectionID cid,
37
CGSConnectionID owner, CGSWindowCount listCapacity,
38
CGSWindowIDList list, CGSWindowCount *listCount);
40
extern CGSError CGSGetScreenRectForWindow (CGSConnectionID cid,
41
CGSWindowID wid, CGSRect *rect);
43
extern CGWindowLevel CGSGetWindowLevel (CGSConnectionID cid,
44
CGSWindowID wid, CGSWindowLevel *level);
46
typedef enum _CGSWindowOrderingMode {
47
kCGSOrderAbove = 1, /* Window is ordered above target. */
48
kCGSOrderBelow = -1, /* Window is ordered below target. */
49
kCGSOrderOut = 0 /* Window is removed from the on-screen window list. */
50
} CGSWindowOrderingMode;
52
extern OSStatus CGSOrderWindow(const CGSConnectionID cid,
53
const CGSWindowID wid, CGSWindowOrderingMode place, CGSWindowID relativeToWindowID);
55
static CGSConnectionID cid = NULL;
57
extern void macosx_log(char *);
60
typedef struct windat {
72
#define MAXWINDAT 4096
73
windat_t macwins[MAXWINDAT];
74
static CGSWindowID _wins_all[MAXWINDAT];
75
static CGSWindowID _wins_mapped[MAXWINDAT];
76
static CGSWindowCount _wins_all_cnt, _wins_mapped_cnt;
77
static int _wins_int[MAXWINDAT];
79
#define WINHISTNUM 32768
81
char whist[WINHISTMAX][WINHISTNUM];
83
int qlook[WINHISTNUM];
87
char is_clipped = 0x4;
88
char is_offscreen = 0x8;
90
extern double dnow(void);
91
extern double dnowx(void);
93
extern int dpy_x, dpy_y;
94
extern int macosx_icon_anim_time;
96
extern void macosx_add_mapnotify(int, int, int);
97
extern void macosx_add_create(int, int);
98
extern void macosx_add_destroy(int, int);
99
extern void macosx_add_visnotify(int, int, int);
104
int macosxCGS_get_qlook(int w) {
105
if (w >= WINHISTNUM) {
111
int macosxCGS_find_index(int w) {
112
static int last_index = -1;
115
if (last_index >= 0) {
116
if (macwins[last_index].win == w) {
121
idx = macosxCGS_get_qlook(w);
123
if (macwins[idx].win == w) {
129
for (idx=0; idx < macwinmax; idx++) {
130
if (macwins[idx].win == w) {
139
extern void usleep(unsigned long usec);
141
extern int usleep(useconds_t usec);
144
int macosxCGS_follow_animation_win(int win, int idx, int grow) {
148
int xp = -1, yp = -1, wp = -1, hp = -1;
155
cid = _CGSDefaultConnection();
162
idx = macosxCGS_find_index(win);
168
while (dnow() < t + 0.001 * macosx_icon_anim_time) {
169
err = CGSGetScreenRectForWindow(cid, win, &rect);
173
x = (int) rect.origin.x;
174
y = (int) rect.origin.y;
175
w = (int) rect.size.width;
176
h = (int) rect.size.height;
181
macwins[idx].width = w;
182
macwins[idx].height = h;
185
if (0) fprintf(stderr, " chase: %03dx%03d+%03d+%03d %d\n", w, h, x, y, win);
186
if (x == xp && y == yp && w == wp && h == hp) {
208
extern int macosx_check_clipped(int win, int *list, int n);
209
extern int macosx_check_offscreen(int win);
211
static int check_clipped(int win) {
213
for (i = 0; i < (int) _wins_mapped_cnt; i++) {
214
win2 = (int) _wins_mapped[i];
218
_wins_int[n++] = win2;
220
return macosx_check_clipped(win, _wins_int, n);
223
static int check_offscreen(int win) {
224
return macosx_check_offscreen(win);
227
extern int macosx_ncache_macmenu;
230
void macosxCGS_get_all_windows(void) {
231
static double last = 0.0;
232
static int totcnt = 0;
233
double dt = 0.0, now = dnow();
234
int i, db = 0, whist_prv = 0, maxwin = 0, whist_skip = 0;
235
CGSWindowCount cap = (CGSWindowCount) MAXWINDAT;
239
CGS_levels[CGS_levelmax++] = (int) kCGDraggingWindowLevel; /* 500 ? */
240
if (0) CGS_levels[CGS_levelmax++] = (int) kCGHelpWindowLevel; /* 102 ? */
241
if (macosx_ncache_macmenu) CGS_levels[CGS_levelmax++] = (int) kCGPopUpMenuWindowLevel; /* 101 pulldown menu */
242
CGS_levels[CGS_levelmax++] = (int) kCGMainMenuWindowLevelKey; /* 24 ? */
243
CGS_levels[CGS_levelmax++] = (int) kCGModalPanelWindowLevel; /* 8 open dialog box */
244
CGS_levels[CGS_levelmax++] = (int) kCGFloatingWindowLevel; /* 3 ? */
245
CGS_levels[CGS_levelmax++] = (int) kCGNormalWindowLevel; /* 0 regular window */
248
cid = _CGSDefaultConnection();
254
if (dt > 0.0 && now < last + dt) {
265
whist_prv = whist_idx++;
270
whist_idx = whist_idx % WINHISTMAX;
271
for (i=0; i < WINHISTNUM; i++) {
272
whist[whist_idx][i] = 0;
277
err = CGSGetWindowList(cid, NULL, cap, _wins_all, &_wins_all_cnt);
279
if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_all_cnt, err);
285
for (i=0; i < (int) _wins_all_cnt; i++) {
287
CGSWindowLevel level;
289
err = CGSGetScreenRectForWindow(cid, _wins_all[i], &rect);
293
if (rect.origin.x == 0 && rect.origin.y == 0) {
294
if (rect.size.width == dpy_x) {
295
if (rect.size.height == dpy_y) {
300
err = CGSGetWindowLevel(cid, _wins_all[i], &level);
304
for (j=0; j<CGS_levelmax; j++) {
305
if ((int) level == CGS_levels[j]) {
314
macwins[macwinmax].level = (int) level;
315
macwins[macwinmax].win = (int) _wins_all[i];
316
macwins[macwinmax].x = (int) rect.origin.x;
317
macwins[macwinmax].y = (int) rect.origin.y;
318
macwins[macwinmax].width = (int) rect.size.width;
319
macwins[macwinmax].height = (int) rect.size.height;
320
macwins[macwinmax].mapped = 0;
321
macwins[macwinmax].clipped = 0;
322
macwins[macwinmax].ncache_only = 0;
323
if (level == kCGPopUpMenuWindowLevel) {
324
macwins[macwinmax].ncache_only = 1;
327
if (0 || db) fprintf(stderr, "i=%03d ID: %06d x: %03d y: %03d w: %03d h: %03d level: %d\n", i, _wins_all[i],
328
(int) rect.origin.x, (int) rect.origin.y,(int) rect.size.width, (int) rect.size.height, (int) level);
330
if (macwins[macwinmax].win < WINHISTNUM) {
331
qlook[macwins[macwinmax].win] = macwinmax;
332
if (macwins[macwinmax].win > maxwin) {
333
maxwin = macwins[macwinmax].win;
340
err = CGSGetOnScreenWindowList(cid, NULL, cap, _wins_mapped, &_wins_mapped_cnt);
342
if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_mapped_cnt, err);
348
for (i=0; i < (int) _wins_mapped_cnt; i++) {
350
int win = (int) _wins_mapped[i];
352
if (0 <= win && win < WINHISTNUM) {
354
if (j >= 0 && macwins[j].win == win) {
359
for (j=0; j < macwinmax; j++) {
360
if (macwins[j].win == win) {
367
macwins[idx].mapped = 1;
372
int nv= 0, NBMAX = 64;
377
for (i=0; i < macwinmax; i++) {
378
int win = macwins[i].win;
381
if (win >= WINHISTNUM) {
385
whist[whist_idx][win] |= is_exist;
386
if (macwins[i].mapped) {
387
whist[whist_idx][win] |= is_mapped;
388
if (check_clipped(win)) {
389
whist[whist_idx][win] |= is_clipped;
390
macwins[i].clipped = 1;
392
if (check_offscreen(win)) {
393
whist[whist_idx][win] |= is_offscreen;
396
whist[whist_idx][win] |= is_offscreen;
399
curr = whist[whist_idx][win];
400
prev = whist[whist_prv][win];
404
} else if ( !(prev & is_mapped) && (curr & is_mapped)) {
406
if (0) fprintf(stderr, "MapNotify: %d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt);
407
macosx_add_mapnotify(win, macwins[i].level, 1);
408
if (0) macosxCGS_follow_animation_win(win, i, 1);
410
} else if ( !(curr & is_mapped) && (prev & is_mapped)) {
412
if (0) fprintf(stderr, "UnmapNotify: %d/%d %d %.4f A tot=%d\n", prev, curr, win, dnowx(), totcnt);
413
macosx_add_mapnotify(win, macwins[i].level, 0);
414
} else if ( !(prev & is_exist) && (curr & is_exist)) {
416
if (0) fprintf(stderr, "CreateNotify:%d/%d %d %.4f whist: %d/%d 0x%x tot=%d\n", prev, curr, win, dnowx(), whist_prv, whist_idx, win, totcnt);
417
macosx_add_create(win, macwins[i].level);
418
if (curr & is_mapped) {
419
if (0) fprintf(stderr, "MapNotify: %d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt);
420
macosx_add_mapnotify(win, macwins[i].level, 1);
425
} else if (nv >= NBMAX) {
427
} else if (!(curr & is_mapped)) {
429
} else if (!(prev & is_mapped)) {
432
} else if (curr & is_clipped) {
433
if (0) fprintf(stderr, "VisibNotify: %d/%d %d OBS tot=%d\n", prev, curr, win, totcnt);
435
nv_lvl[nv] = macwins[i].level;
438
if (0) fprintf(stderr, "VisibNotify: %d/%d %d UNOBS tot=%d\n", prev, curr, win, totcnt);
440
nv_lvl[nv] = macwins[i].level;
444
if ( !(prev & is_clipped) && (curr & is_clipped) ) {
445
if (0) fprintf(stderr, "VisibNotify: %d/%d %d OBS tot=%d\n", prev, curr, win, totcnt);
447
nv_lvl[nv] = macwins[i].level;
449
} else if ( (prev & is_clipped) && !(curr & is_clipped) ) {
450
if (0) fprintf(stderr, "VisibNotify: %d/%d %d UNOBS tot=%d\n", prev, curr, win, totcnt);
452
nv_lvl[nv] = macwins[i].level;
457
for (i=0; i < maxwin; i++) {
468
lvl = macwins[q].level;
470
curr = whist[whist_idx][win];
471
prev = whist[whist_prv][win];
472
if (!(curr & is_exist) && (prev & is_exist)) {
473
if (prev & is_mapped) {
474
if (0) fprintf(stderr, "UnmapNotify: %d/%d %d %.4f B tot=%d\n", prev, curr, win, dnowx(), totcnt);
475
macosx_add_mapnotify(win, lvl, 0);
478
if (0) fprintf(stderr, "DestroNotify:%d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt);
479
macosx_add_destroy(win, lvl);
484
for (k = 0; k < nv; k++) {
485
macosx_add_visnotify(nv_win[k], nv_lvl[k], nv_vis[k]);
492
NSLock *pblock = nil;
493
NSString *pbstr = nil;
494
NSString *cuttext = nil;
497
NSStringEncoding pbenc = NSWindowsCP1252StringEncoding;
499
void macosxGCS_initpb(void) {
500
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
501
pblock = [[NSLock alloc] init];
502
if (![NSPasteboard generalPasteboard]) {
503
macosx_log("macosxGCS_initpb: **PASTEBOARD INACCESSIBLE**.\n");
504
macosx_log("macosxGCS_initpb: Clipboard exchange will NOT work.\n");
505
macosx_log("macosxGCS_initpb: Start x11vnc *inside* Aqua for Clipboard.\n");
507
pbstr = [[NSString alloc] initWithString:@"\e<PASTEBOARD INACCESSIBLE>\e"];
512
void macosxGCS_set_pasteboard(char *str, int len) {
513
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
517
cuttext = [[NSString alloc] initWithData:[NSData dataWithBytes:str length:len] encoding: pbenc];
518
if ([[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]) {
520
[[NSPasteboard generalPasteboard] setString:cuttext forType:NSStringPboardType];
522
fprintf(stderr, "macosxGCS_set_pasteboard: problem writing to pasteboard\n");
525
fprintf(stderr, "macosxGCS_set_pasteboard: problem writing to pasteboard\n");
534
extern void macosx_send_sel(char *, int);
536
void macosxGCS_poll_pb(void) {
538
static double dlast = 0.0;
541
if (now < dlast + 0.2) {
547
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
549
if (pbcnt != [[NSPasteboard generalPasteboard] changeCount]) {
550
pbcnt = [[NSPasteboard generalPasteboard] changeCount];
553
if ([[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]) {
554
pbstr = [[[NSPasteboard generalPasteboard] stringForType:NSStringPboardType] copy];
556
NSData *str = [pbstr dataUsingEncoding:pbenc allowLossyConversion:YES];
558
macosx_send_sel((char *) [str bytes], [str length]);
569
#endif /* __APPLE__ */