11
int xfixes_present = 0;
13
int got_xfixes_cursor_notify = 0;
14
int cursor_changes = 0;
15
int alpha_threshold = 240;
16
double alpha_frac = 0.33;
22
void first_cursor(void);
23
void setup_cursors_and_push(void);
24
void initialize_xfixes(void);
25
int known_cursors_mode(char *s);
26
void initialize_cursors_mode(void);
27
int get_which_cursor(void);
28
void restore_cursor_shape_updates(rfbScreenInfoPtr s);
29
void disable_cursor_shape_updates(rfbScreenInfoPtr s);
30
int cursor_shape_updates_clients(rfbScreenInfoPtr s);
31
int cursor_pos_updates_clients(rfbScreenInfoPtr s);
32
void cursor_position(int x, int y);
33
void set_no_cursor(void);
34
void set_warrow_cursor(void);
35
int set_cursor(int x, int y, int which);
36
int check_x11_pointer(void);
37
int store_cursor(int serial, unsigned long *data, int w, int h, int cbpp, int xhot, int yhot);
38
unsigned long get_cursor_serial(int mode);
41
typedef struct win_str_info {
47
typedef struct cursor_info {
48
char *data; /* data and mask pointers */
50
int wx, wy; /* size of cursor */
51
int sx, sy; /* shift to its centering point */
52
int reverse; /* swap black and white */
57
static void curs_copy(cursor_info_t *dest, cursor_info_t *src);
58
static void setup_cursors(void);
59
static void set_rfb_cursor(int which);
60
static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo);
61
static rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h,
62
int xhot, int yhot, int Bpp);
63
static int get_exact_cursor(int init);
64
static void set_cursor_was_changed(rfbScreenInfoPtr s);
68
* Here begins a bit of a mess to experiment with multiple cursors
69
* drawn on the remote background ...
71
static void curs_copy(cursor_info_t *dest, cursor_info_t *src) {
72
if (src->data != NULL) {
73
dest->data = strdup(src->data);
77
if (src->mask != NULL) {
78
dest->mask = strdup(src->mask);
86
dest->reverse = src->reverse;
89
if (rotating && rotating_cursors && dest->data != NULL) {
91
rotate_curs(dest->data, src->data, src->wx, src->wy, 1);
92
rotate_curs(dest->mask, src->mask, src->wx, src->wy, 1);
93
rotate_coords(dest->sx, dest->sy, &tx, &ty, src->wx, src->wy);
96
if (! rotating_same) {
104
static char* curs_empty_data =
108
static char* curs_empty_mask =
111
static cursor_info_t cur_empty = {NULL, NULL, 2, 2, 0, 0, 0, NULL};
114
static char* curs_dot_data =
118
static char* curs_dot_mask =
121
static cursor_info_t cur_dot = {NULL, NULL, 2, 2, 0, 0, 0, NULL};
125
static char* curs_arrow_data =
145
static char* curs_arrow_mask =
164
static cursor_info_t cur_arrow = {NULL, NULL, 18, 18, 0, 0, 1, NULL};
166
static char* curs_arrow2_data =
186
static char* curs_arrow2_mask =
205
static cursor_info_t cur_arrow2 = {NULL, NULL, 18, 18, 0, 0, 0, NULL};
207
static char* curs_arrow3_data =
225
static char* curs_arrow3_mask =
243
static cursor_info_t cur_arrow3 = {NULL, NULL, 16, 16, 0, 0, 1, NULL};
245
static char* curs_arrow4_data =
263
static char* curs_arrow4_mask =
281
static cursor_info_t cur_arrow4 = {NULL, NULL, 16, 16, 0, 0, 0, NULL};
283
static char* curs_arrow5_data =
300
static char* curs_arrow5_mask =
317
static cursor_info_t cur_arrow5 = {NULL, NULL, 15, 15, 0, 0, 1, NULL};
319
static char* curs_arrow6_data =
336
static char* curs_arrow6_mask =
353
static cursor_info_t cur_arrow6 = {NULL, NULL, 15, 15, 0, 0, 0, NULL};
355
int alt_arrow_max = 6;
357
* It turns out we can at least detect mouse is on the root window so
358
* show it (under -cursor X) with this familiar cursor...
360
static char* curs_root_data =
380
static char* curs_root_mask =
399
static cursor_info_t cur_root = {NULL, NULL, 18, 18, 8, 8, 1, NULL};
401
static char* curs_fleur_data =
419
static char* curs_fleur_mask =
437
static cursor_info_t cur_fleur = {NULL, NULL, 16, 16, 8, 8, 1, NULL};
439
static char* curs_plus_data =
453
static char* curs_plus_mask =
466
static cursor_info_t cur_plus = {NULL, NULL, 12, 12, 5, 6, 1, NULL};
468
static char* curs_xterm_data =
486
static char* curs_xterm_mask =
503
static cursor_info_t cur_xterm = {NULL, NULL, 16, 16, 8, 8, 1, NULL};
534
#define CURS_DYN_MIN CURS_DYN1
535
#define CURS_DYN_MAX CURS_DYN16
536
#define CURS_DYN_NUM (CURS_DYN_MAX - CURS_DYN_MIN + 1)
539
static cursor_info_t *cursors[CURS_MAX];
541
void first_cursor(void) {
546
screen->cursor = NULL;
548
got_xfixes_cursor_notify++;
549
set_rfb_cursor(get_which_cursor());
550
set_cursor_was_changed(screen);
554
static void setup_cursors(void) {
555
rfbCursorPtr rfb_curs;
558
static int first = 1;
561
rfbLog("setting up %d cursors...\n", CURS_MAX);
565
for (i=0; i<CURS_MAX; i++) {
572
screen->cursor = NULL;
573
LOCK(screen->cursorMutex);
576
for (i=0; i<CURS_MAX; i++) {
579
/* clear out any existing ones: */
582
/* this is the rfbCursor part: */
583
if (ci->rfb->richSource) {
584
free(ci->rfb->richSource);
585
ci->rfb->richSource = NULL;
587
if (ci->rfb->source) {
588
free(ci->rfb->source);
589
ci->rfb->source = NULL;
593
ci->rfb->mask = NULL;
610
/* create new struct: */
611
ci = (cursor_info_t *) malloc(sizeof(cursor_info_t));
623
/* clear any xfixes cursor cache (no freeing is done) */
626
/* manually fill in the data+masks: */
627
cur_empty.data = curs_empty_data;
628
cur_empty.mask = curs_empty_mask;
630
cur_dot.data = curs_dot_data;
631
cur_dot.mask = curs_dot_mask;
633
cur_arrow.data = curs_arrow_data;
634
cur_arrow.mask = curs_arrow_mask;
635
cur_arrow2.data = curs_arrow2_data;
636
cur_arrow2.mask = curs_arrow2_mask;
637
cur_arrow3.data = curs_arrow3_data;
638
cur_arrow3.mask = curs_arrow3_mask;
639
cur_arrow4.data = curs_arrow4_data;
640
cur_arrow4.mask = curs_arrow4_mask;
641
cur_arrow5.data = curs_arrow5_data;
642
cur_arrow5.mask = curs_arrow5_mask;
643
cur_arrow6.data = curs_arrow6_data;
644
cur_arrow6.mask = curs_arrow6_mask;
646
cur_root.data = curs_root_data;
647
cur_root.mask = curs_root_mask;
649
cur_plus.data = curs_plus_data;
650
cur_plus.mask = curs_plus_mask;
652
cur_fleur.data = curs_fleur_data;
653
cur_fleur.mask = curs_fleur_mask;
655
cur_xterm.data = curs_xterm_data;
656
cur_xterm.mask = curs_xterm_mask;
658
curs_copy(cursors[CURS_EMPTY], &cur_empty); n++;
659
curs_copy(cursors[CURS_DOT], &cur_dot); n++;
661
if (alt_arrow < 1 || alt_arrow > alt_arrow_max) {
664
if (alt_arrow == 1) {
665
curs_copy(cursors[CURS_ARROW], &cur_arrow); n++;
666
} else if (alt_arrow == 2) {
667
curs_copy(cursors[CURS_ARROW], &cur_arrow2); n++;
668
} else if (alt_arrow == 3) {
669
curs_copy(cursors[CURS_ARROW], &cur_arrow3); n++;
670
} else if (alt_arrow == 4) {
671
curs_copy(cursors[CURS_ARROW], &cur_arrow4); n++;
672
} else if (alt_arrow == 5) {
673
curs_copy(cursors[CURS_ARROW], &cur_arrow5); n++;
674
} else if (alt_arrow == 6) {
675
curs_copy(cursors[CURS_ARROW], &cur_arrow6); n++;
678
curs_copy(cursors[CURS_ARROW], &cur_arrow); n++;
680
curs_copy(cursors[CURS_WARROW], &cur_arrow2); n++;
682
curs_copy(cursors[CURS_ROOT], &cur_root); n++;
683
curs_copy(cursors[CURS_WM], &cur_fleur); n++;
684
curs_copy(cursors[CURS_TERM], &cur_xterm); n++;
685
curs_copy(cursors[CURS_PLUS], &cur_plus); n++;
687
if (scale_cursor_str) {
688
scale = scale_cursor_str;
689
} else if (scaling && scale_str) {
692
/* scale = NULL zeroes everything */
693
parse_scale_string(scale, &scale_cursor_fac, &scaling_cursor,
694
&scaling_cursor_blend, &j, &j, &scaling_cursor_interpolate,
695
&scale_cursor_numer, &scale_cursor_denom);
697
for (i=0; i<n; i++) {
698
/* create rfbCursors for the special cursors: */
700
cursor_info_t *ci = cursors[i];
702
if (scaling_cursor && scale_cursor_fac != 1.0) {
704
unsigned long *pixels;
709
pixels = (unsigned long *) malloc(w * h
710
* sizeof(unsigned long));
713
for (y=0; y<h; y++) {
714
for (x=0; x<w; x++) {
715
char d = ci->data[k];
716
char m = ci->mask[k];
724
if (d == ' ' && m == ' ') {
727
} else if (d != ' ') {
734
} else if (m != ' ') {
746
rfb_curs = pixels2curs(pixels, w, h, ci->sx, ci->sy,
753
/* standard X cursor */
754
rfb_curs = rfbMakeXCursor(ci->wx, ci->wy,
758
rfb_curs->foreRed = 0x0000;
759
rfb_curs->foreGreen = 0x0000;
760
rfb_curs->foreBlue = 0x0000;
761
rfb_curs->backRed = 0xffff;
762
rfb_curs->backGreen = 0xffff;
763
rfb_curs->backBlue = 0xffff;
765
rfb_curs->alphaSource = NULL;
767
rfb_curs->xhot = ci->sx;
768
rfb_curs->yhot = ci->sy;
769
rfb_curs->cleanup = FALSE;
770
rfb_curs->cleanupSource = FALSE;
771
rfb_curs->cleanupMask = FALSE;
772
rfb_curs->cleanupRichSource = FALSE;
774
if (bpp == 8 && indexed_color) {
776
* use richsource in PseudoColor for better
777
* looking cursors (i.e. two-color).
780
int black = 0, white = 1;
783
if (dpy) { /* raw_fb hack */
784
black = BlackPixel(dpy, scr);
785
white = WhitePixel(dpy, scr);
788
rfb_curs->richSource = (unsigned char *)
789
calloc(ci->wx * ci->wy, 1);
791
for (y = 0; y < ci->wy; y++) {
792
for (x = 0; x < ci->wx; x++) {
795
if (d == ' ' && m == ' ') {
798
} else if (m != ' ' && d == ' ') {
810
*(rfb_curs->richSource+k) =
820
UNLOCK(screen->cursorMutex);
828
void setup_cursors_and_push(void) {
834
* Descends window tree at pointer until the window cursor matches the current
835
* cursor. So far only used to detect if mouse is on root background or not.
836
* (returns 0 in that case, 1 otherwise).
839
static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
842
if (!depth || !w || !winfo) {}
846
int i, rx, ry, wx, wy;
849
int descend, maxtries = 10;
850
char *name, *s = multiple_cursors_mode;
851
static XClassHint *classhint = NULL;
853
XErrorHandler old_handler;
859
if (!strcmp(s, "default") || !strcmp(s, "X") || !strcmp(s, "arrow")) {
863
*(winfo->wm_name) = '\0';
864
*(winfo->res_name) = '\0';
865
*(winfo->res_class) = '\0';
868
/* some times a window can go away before we get to it */
870
old_handler = XSetErrorHandler(trap_xerror);
877
if (descend >= maxtries - 1) {
880
if ( XTestCompareCurrentCursorWithWindow_wr(dpy, c) ) {
883
/* TBD: query_pointer() */
884
XQueryPointer_wr(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &mask);
888
int got_wm_name = 0, got_res_name = 0, got_res_class = 0;
891
classhint = XAllocClassHint();
894
for (i = descend; i >=0; i--) {
900
if (! got_wm_name && XFetchName(dpy, c, &name)) {
903
strcpy(winfo->wm_name, name);
909
if (classhint && (! got_res_name || ! got_res_class)) {
910
if (XGetClassHint(dpy, c, classhint)) {
912
p = classhint->res_name;
914
if (*p != '\0' && ! got_res_name) {
915
strcpy(winfo->res_name, p);
919
classhint->res_name = NULL;
921
p = classhint->res_class;
923
if (*p != '\0' && ! got_res_class) {
924
strcpy(winfo->res_class, p);
928
classhint->res_class = NULL;
935
XSetErrorHandler(old_handler);
945
void initialize_xfixes(void) {
946
#if LIBVNCSERVER_HAVE_LIBXFIXES
947
if (xfixes_present) {
950
XFixesSelectCursorInput(dpy, rootwin,
951
XFixesDisplayCursorNotifyMask);
953
XFixesSelectCursorInput(dpy, rootwin, 0);
960
static rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h,
961
int xhot, int yhot, int Bpp) {
963
static unsigned long black = 0, white = 1;
964
static int first = 1;
965
char *bitmap, *rich, *alpha;
966
char *pixels_new = NULL;
967
int n_opaque, n_trans, n_alpha, len, histo[256];
968
int send_alpha = 0, alpha_shift = 0, thresh;
971
if (first && dpy) { /* raw_fb hack */
973
black = BlackPixel(dpy, scr);
974
white = WhitePixel(dpy, scr);
979
if (cmap8to24 && cmap8to24_fb && depth == 8) {
985
if (scaling_cursor && scale_cursor_fac != 1.0) {
987
char *pixels_use = (char *) pixels;
988
unsigned int *pixels32 = NULL;
993
w = scale_round(W, scale_cursor_fac);
994
h = scale_round(H, scale_cursor_fac);
996
pixels_new = (char *) malloc(4*w*h);
998
if (sizeof(unsigned long) == 8) {
1001
* to avoid 64bpp code in scale_rect() we knock
1002
* down to unsigned int on 64bit machines:
1004
pixels32 = (unsigned int*) malloc(4*W*H);
1005
for (j=0; j<H; j++) {
1006
for (i=0; i<W; i++) {
1007
*(pixels32+k) = 0xffffffff & (*(pixels+k));
1011
pixels_use = (char *) pixels32;
1014
scale_rect(scale_cursor_fac, scaling_cursor_blend,
1015
scaling_cursor_interpolate,
1016
4, pixels_use, 4*W, pixels_new, 4*w,
1017
W, H, w, h, 0, 0, W, H, 0);
1019
if (sizeof(unsigned long) == 8) {
1021
unsigned long *pixels64;
1022
unsigned int* source = (unsigned int*) pixels_new;
1024
* now knock it back up to unsigned long:
1026
pixels64 = (unsigned long*) malloc(8*w*h);
1027
for (j=0; j<h; j++) {
1028
for (i=0; i<w; i++) {
1029
*(pixels64+k) = (unsigned long) (*(source+k));
1034
pixels_new = (char *) pixels64;
1041
pixels = (unsigned long *) pixels_new;
1043
xhot = scale_round(xhot, scale_cursor_fac);
1044
yhot = scale_round(yhot, scale_cursor_fac);
1048
/* for bitmap data */
1049
bitmap = (char *) malloc(len+1);
1052
/* for rich cursor pixel data */
1053
rich = (char *)calloc(Bpp*len, 1);
1054
alpha = (char *)calloc(1*len, 1);
1059
for (i=0; i<256; i++) {
1064
for (y = 0; y < h; y++) {
1065
for (x = 0; x < w; x++) {
1068
a = 0xff000000 & (*(pixels+i));
1069
a = a >> 24; /* alpha channel */
1074
if (a < (unsigned int) alpha_threshold) {
1088
if (main_red_shift == 24 || main_green_shift == 24 ||
1089
main_blue_shift == 24) {
1090
alpha_shift = 0; /* XXX correct? */
1093
if (n_opaque >= alpha_frac * n_alpha) {
1094
thresh = alpha_threshold;
1097
for (i=255; i>=0; i--) {
1098
n_opaque += histo[i];
1100
if (n_opaque >= alpha_frac * n_alpha) {
1107
for (y = 0; y < h; y++) {
1108
for (x = 0; x < w; x++) {
1109
unsigned long r, g, b, a;
1113
a = 0xff000000 & (*(pixels+i));
1114
a = a >> 24; /* alpha channel */
1116
if (a < (unsigned int) thresh) {
1122
r = 0x00ff0000 & (*(pixels+i));
1123
g = 0x0000ff00 & (*(pixels+i));
1124
b = 0x000000ff & (*(pixels+i));
1125
r = r >> 16; /* red */
1126
g = g >> 8; /* green */
1127
b = b >> 0; /* blue */
1129
if (alpha_remove && a != 0) {
1133
if (r > 255) r = 255;
1134
if (g > 255) g = 255;
1135
if (b > 255) b = 255;
1138
if (indexed_color) {
1140
* Choose black or white for
1143
int value = (r+g+b)/3;
1151
* Otherwise map the RGB data onto
1152
* the framebuffer format:
1154
r = (main_red_max * r)/255;
1155
g = (main_green_max * g)/255;
1156
b = (main_blue_max * b)/255;
1158
ui |= (r << main_red_shift);
1159
ui |= (g << main_green_shift);
1160
ui |= (b << main_blue_shift);
1162
ui |= (a << alpha_shift);
1166
/* insert value into rich source: */
1170
*((unsigned char *)p)
1171
= (unsigned char) ui;
1172
} else if (Bpp == 2) {
1173
*((unsigned short *)p)
1174
= (unsigned short) ui;
1175
} else if (Bpp == 3) {
1176
*((unsigned char *)p)
1177
= (unsigned char) ((ui & 0x0000ff) >> 0);
1178
*((unsigned char *)(p+1))
1179
= (unsigned char) ((ui & 0x00ff00) >> 8);
1180
*((unsigned char *)(p+2))
1181
= (unsigned char) ((ui & 0xff0000) >> 16);
1182
} else if (Bpp == 4) {
1183
*((unsigned int *)p)
1184
= (unsigned int) ui;
1187
/* insert alpha value into alpha source: */
1189
*((unsigned char *)p) = (unsigned char) a;
1195
/* create the cursor with the bitmap: */
1196
c = rfbMakeXCursor(w, h, bitmap, bitmap);
1203
/* set up the cursor parameters: */
1207
c->cleanupSource = FALSE;
1208
c->cleanupMask = FALSE;
1209
c->cleanupRichSource = FALSE;
1210
c->richSource = (unsigned char *) rich;
1212
/* zeroes mean interpolate the rich cursor somehow and use B+W */
1222
if (alpha_blend && !indexed_color) {
1223
c->alphaSource = (unsigned char *) alpha;
1224
c->alphaPreMultiplied = TRUE;
1227
c->alphaSource = NULL;
1232
static unsigned long last_cursor = 0;
1233
static int last_index = 0;
1234
static time_t curs_times[CURS_MAX];
1235
static unsigned long curs_index[CURS_MAX];
1237
unsigned long get_cursor_serial(int mode) {
1240
} else if (mode == 1) {
1241
return (unsigned long) last_index;
1243
return (unsigned long) last_index;
1247
static int get_exact_cursor(int init) {
1248
int which = CURS_ARROW;
1251
/* zero out our cache (cursors are not freed) */
1253
for (i=0; i<CURS_MAX; i++) {
1263
if (macosx_console) {
1264
return macosx_get_cursor();
1268
if (rawfb_vnc_reflect) {
1269
int last_idx = (int) get_cursor_serial(1);
1275
if (xfixes_present && dpy) {
1276
#if LIBVNCSERVER_HAVE_LIBXFIXES
1277
int last_idx = (int) get_cursor_serial(1);
1278
XFixesCursorImage *xfc;
1284
if (! got_xfixes_cursor_notify && xfixes_base_event_type) {
1285
/* try again for XFixesCursorNotify event */
1288
if (XCheckTypedEvent(dpy, xfixes_base_event_type +
1289
XFixesCursorNotify, &xev)) {
1290
got_xfixes_cursor_notify++;
1294
if (! got_xfixes_cursor_notify) {
1295
/* evidently no cursor change, just return last one */
1298
got_xfixes_cursor_notify = 0;
1300
/* retrieve the cursor info + pixels from server: */
1302
xfc = XFixesGetCursorImage(dpy);
1309
which = store_cursor(xfc->cursor_serial, xfc->pixels,
1310
xfc->width, xfc->height, 32, xfc->xhot, xfc->yhot);
1320
int store_cursor(int serial, unsigned long *data, int w, int h, int cbpp,
1321
int xhot, int yhot) {
1322
int which = CURS_ARROW;
1324
time_t oldtime, now;
1327
fprintf(stderr, "sc: %d %d/%d %d - %d %d\n", serial, w, h, cbpp, xhot, yhot);
1330
oldest = CURS_DYN_MIN;
1331
if (screen && screen->cursor == cursors[oldest]->rfb) {
1334
oldtime = curs_times[oldest];
1336
for (i = CURS_DYN_MIN; i <= CURS_DYN_MAX; i++) {
1337
if (screen && screen->cursor == cursors[i]->rfb) {
1339
} else if (curs_times[i] < oldtime) {
1340
/* watch for oldest one to overwrite */
1342
oldtime = curs_times[i];
1344
if (serial == (int) curs_index[i]) {
1346
* got a hit with an existing cursor,
1350
if (now > curs_times[i] + 1) {
1354
last_cursor = curs_index[i];
1355
curs_times[i] = now;
1361
/* we need to create the cursor and overwrite oldest */
1363
if (cursors[use]->rfb) {
1364
/* clean up oldest if it exists */
1365
if (cursors[use]->rfb->richSource) {
1366
free(cursors[use]->rfb->richSource);
1367
cursors[use]->rfb->richSource = NULL;
1369
if (cursors[use]->rfb->alphaSource) {
1370
free(cursors[use]->rfb->alphaSource);
1371
cursors[use]->rfb->alphaSource = NULL;
1373
if (cursors[use]->rfb->source) {
1374
free(cursors[use]->rfb->source);
1375
cursors[use]->rfb->source = NULL;
1377
if (cursors[use]->rfb->mask) {
1378
free(cursors[use]->rfb->mask);
1379
cursors[use]->rfb->mask = NULL;
1381
free(cursors[use]->rfb);
1382
cursors[use]->rfb = NULL;
1385
if (rotating && rotating_cursors) {
1389
dst = (char *) malloc(w * h * cbpp/8);
1390
rotate_curs(dst, (char *) data, w, h, cbpp/8);
1392
memcpy(data, dst, w * h * cbpp/8);
1395
rotate_coords(xhot, yhot, &tx, &ty, w, h);
1398
if (! rotating_same) {
1405
/* place cursor into our collection */
1406
cursors[use]->rfb = pixels2curs(data, w, h, xhot, yhot, bpp/8);
1408
/* update time and serial index: */
1409
curs_times[use] = now;
1410
curs_index[use] = serial;
1412
last_cursor = serial;
1419
int known_cursors_mode(char *s) {
1421
* default: see initialize_cursors_mode() for default behavior.
1422
* arrow: unchanging white arrow.
1423
* Xn*: show X on root background. Optional n sets treedepth.
1424
* some: do the heuristics for root, wm, term detection.
1425
* most: if display have overlay or xfixes, show all cursors,
1426
* otherwise do the same as "some"
1427
* none: show no cursor.
1429
if (strcmp(s, "default") && strcmp(s, "arrow") && *s != 'X' &&
1430
strcmp(s, "some") && strcmp(s, "most") && strcmp(s, "none")) {
1437
void initialize_cursors_mode(void) {
1438
char *s = multiple_cursors_mode;
1439
if (!s || !known_cursors_mode(s)) {
1440
rfbLog("unknown cursors mode: %s\n", s);
1441
rfbLog("resetting cursors mode to \"default\"\n");
1442
if (multiple_cursors_mode) free(multiple_cursors_mode);
1443
multiple_cursors_mode = strdup("default");
1444
s = multiple_cursors_mode;
1446
if (!strcmp(s, "none")) {
1449
/* we do NOT set show_cursor = 1, let the caller do that */
1452
show_multiple_cursors = 0;
1454
if (!strcmp(s, "default")) {
1455
if(multiple_cursors_mode) free(multiple_cursors_mode);
1456
multiple_cursors_mode = strdup("X");
1457
s = multiple_cursors_mode;
1459
if (*s == 'X' || !strcmp(s, "some") || !strcmp(s, "most")) {
1460
show_multiple_cursors = 1;
1462
show_multiple_cursors = 0;
1463
/* hmmm, some bug going back to arrow mode.. */
1464
set_rfb_cursor(CURS_ARROW);
1467
set_cursor_was_changed(screen);
1471
screen->cursor = NULL;
1472
set_cursor_was_changed(screen);
1477
int get_which_cursor(void) {
1478
int which = CURS_ARROW;
1481
if (show_multiple_cursors) {
1483
static win_str_info_t winfo;
1484
static int first = 1, depth_cutoff = -1;
1486
XErrorHandler old_handler;
1489
if (drag_in_progress || button_mask) {
1490
/* XXX not exactly what we want for menus */
1491
if (! cursor_drag_changes) {
1496
if (!strcmp(multiple_cursors_mode, "arrow")) {
1497
/* should not happen... */
1499
} else if (!strcmp(multiple_cursors_mode, "default")) {
1501
} else if (!strcmp(multiple_cursors_mode, "X")) {
1503
} else if (!strcmp(multiple_cursors_mode, "some")) {
1505
} else if (!strcmp(multiple_cursors_mode, "most")) {
1509
if (rawfb_vnc_reflect && mode > -1) {
1510
return get_exact_cursor(0);
1513
if ((xfixes_present && use_xfixes) || macosx_console) {
1514
if (db) fprintf(stderr, "get_which_cursor call get_exact_cursor\n");
1515
return get_exact_cursor(0);
1519
if (depth_cutoff < 0) {
1521
if (sscanf(multiple_cursors_mode, "X%d", &din) == 1) {
1529
winfo.wm_name = (char *) malloc(1024);
1530
winfo.res_name = (char *) malloc(1024);
1531
winfo.res_class = (char *) malloc(1024);
1535
tree_descend_cursor(&depth, &win, &winfo);
1537
if (depth <= depth_cutoff && !subwin) {
1540
} else if (mode == 2 || mode == 3) {
1543
/* apply crude heuristics to choose a cursor... */
1545
int ratio = 10, x, y;
1546
unsigned int w, h, bw, d;
1552
old_handler = XSetErrorHandler(trap_xerror);
1554
/* "narrow" windows are WM */
1555
if (XGetGeometry(dpy, win, &r, &x, &y, &w, &h,
1557
if (w > ratio * h || h > ratio * w) {
1561
XSetErrorHandler(old_handler);
1565
if (!r || !d || !bw || !h || !w || !y || !x || !ratio || !old_handler) {}
1568
if (which == which0) {
1569
/* the string "term" means I-beam. */
1571
lowercase(winfo.res_name);
1572
lowercase(winfo.res_class);
1573
name = winfo.res_name;
1574
class = winfo.res_class;
1575
if (strstr(name, "term")) {
1577
} else if (strstr(class, "term")) {
1579
} else if (strstr(name, "text")) {
1581
} else if (strstr(class, "text")) {
1583
} else if (strstr(name, "onsole")) {
1585
} else if (strstr(class, "onsole")) {
1587
} else if (strstr(name, "cmdtool")) {
1589
} else if (strstr(class, "cmdtool")) {
1591
} else if (strstr(name, "shelltool")) {
1593
} else if (strstr(class, "shelltool")) {
1599
if (db) fprintf(stderr, "get_which_cursor which: %d\n", which);
1603
static void set_cursor_was_changed(rfbScreenInfoPtr s) {
1604
rfbClientIteratorPtr iter;
1610
iter = rfbGetClientIterator(s);
1611
while( (cl = rfbClientIteratorNext(iter)) ) {
1612
cl->cursorWasChanged = TRUE;
1614
rfbReleaseClientIterator(iter);
1619
static void set_cursor_was_moved(rfbScreenInfoPtr s) {
1620
rfbClientIteratorPtr iter;
1626
iter = rfbGetClientIterator(s);
1627
while( (cl = rfbClientIteratorNext(iter)) ) {
1628
cl->cursorWasMoved = TRUE;
1630
rfbReleaseClientIterator(iter);
1634
void restore_cursor_shape_updates(rfbScreenInfoPtr s) {
1635
rfbClientIteratorPtr iter;
1639
if (! s || ! s->clientHead) {
1642
iter = rfbGetClientIterator(s);
1643
while( (cl = rfbClientIteratorNext(iter)) ) {
1645
ClientData *cd = (ClientData *) cl->clientData;
1650
if (cd->had_cursor_shape_updates) {
1651
rfbLog("restoring enableCursorShapeUpdates for client"
1653
cl->enableCursorShapeUpdates = TRUE;
1656
if (cd->had_cursor_pos_updates) {
1657
rfbLog("restoring enableCursorPosUpdates for client"
1659
cl->enableCursorPosUpdates = TRUE;
1663
cl->cursorWasChanged = TRUE;
1667
rfbReleaseClientIterator(iter);
1670
void disable_cursor_shape_updates(rfbScreenInfoPtr s) {
1671
rfbClientIteratorPtr iter;
1673
static int changed = 0;
1676
if (! s || ! s->clientHead) {
1679
if (unixpw_in_progress) return;
1681
iter = rfbGetClientIterator(s);
1682
while( (cl = rfbClientIteratorNext(iter)) ) {
1684
cd = (ClientData *) cl->clientData;
1686
if (cl->enableCursorShapeUpdates) {
1688
cd->had_cursor_shape_updates = 1;
1691
if (debug_pointer) {
1692
rfbLog("%s disable HCSU\n", cl->host);
1695
if (cl->enableCursorPosUpdates) {
1697
cd->had_cursor_pos_updates = 1;
1700
if (debug_pointer) {
1701
rfbLog("%s disable HCPU\n", cl->host);
1705
cl->enableCursorShapeUpdates = FALSE;
1706
cl->enableCursorPosUpdates = FALSE;
1707
cl->cursorWasChanged = FALSE;
1709
rfbReleaseClientIterator(iter);
1716
int cursor_shape_updates_clients(rfbScreenInfoPtr s) {
1717
rfbClientIteratorPtr iter;
1724
iter = rfbGetClientIterator(s);
1725
while( (cl = rfbClientIteratorNext(iter)) ) {
1726
if (cl->enableCursorShapeUpdates) {
1730
rfbReleaseClientIterator(iter);
1734
int cursor_noshape_updates_clients(rfbScreenInfoPtr s) {
1735
rfbClientIteratorPtr iter;
1742
iter = rfbGetClientIterator(s);
1743
while( (cl = rfbClientIteratorNext(iter)) ) {
1744
if (!cl->enableCursorShapeUpdates) {
1748
rfbReleaseClientIterator(iter);
1752
int cursor_pos_updates_clients(rfbScreenInfoPtr s) {
1753
rfbClientIteratorPtr iter;
1760
iter = rfbGetClientIterator(s);
1761
while( (cl = rfbClientIteratorNext(iter)) ) {
1762
if (cl->enableCursorPosUpdates) {
1766
rfbReleaseClientIterator(iter);
1771
* Record rfb cursor position screen->cursorX, etc (a la defaultPtrAddEvent())
1772
* Then set up for sending rfbCursorPosUpdates back
1773
* to clients that understand them. This seems to be TightVNC specific.
1775
void cursor_position(int x, int y) {
1776
rfbClientIteratorPtr iter;
1778
int cnt = 0, nonCursorPosUpdates_clients = 0;
1779
int x_in = x, y_in = y;
1781
/* x and y are current positions of X11 pointer on the X11 display */
1787
x = ((double) x / dpy_x) * scaled_x;
1788
x = nfix(x, scaled_x);
1789
y = ((double) y / dpy_y) * scaled_y;
1790
y = nfix(y, scaled_y);
1796
if (x >= dpy_x) x = dpy_x-1;
1797
if (y >= dpy_y) y = dpy_y-1;
1800
if (x == screen->cursorX && y == screen->cursorY) {
1804
LOCK(screen->cursorMutex);
1805
screen->cursorX = x;
1806
screen->cursorY = y;
1807
UNLOCK(screen->cursorMutex);
1809
iter = rfbGetClientIterator(screen);
1810
while( (cl = rfbClientIteratorNext(iter)) ) {
1811
if (! cl->enableCursorPosUpdates) {
1812
nonCursorPosUpdates_clients++;
1815
if (! cursor_pos_updates) {
1818
if (cl == last_pointer_client) {
1820
* special case if this client was the last one to
1821
* send a pointer position.
1823
if (x_in == cursor_x && y_in == cursor_y) {
1824
cl->cursorWasMoved = FALSE;
1826
/* an X11 app evidently warped the pointer */
1827
if (debug_pointer) {
1828
rfbLog("cursor_position: warp "
1829
"detected dx=%3d dy=%3d\n",
1830
cursor_x - x, cursor_y - y);
1832
cl->cursorWasMoved = TRUE;
1836
cl->cursorWasMoved = TRUE;
1840
rfbReleaseClientIterator(iter);
1842
if (debug_pointer && cnt) {
1843
rfbLog("cursor_position: sent position x=%3d y=%3d to %d"
1844
" clients\n", x, y, cnt);
1848
static void set_rfb_cursor(int which) {
1850
if (! show_cursor) {
1857
if (!cursors[which] || !cursors[which]->rfb) {
1858
rfbLog("non-existent cursor: which=%d\n", which);
1861
rfbSetCursor(screen, cursors[which]->rfb);
1865
void set_no_cursor(void) {
1866
set_rfb_cursor(CURS_EMPTY);
1869
void set_warrow_cursor(void) {
1870
set_rfb_cursor(CURS_WARROW);
1873
int set_cursor(int x, int y, int which) {
1874
static int last = -1;
1875
int changed_cursor = 0;
1877
if (x || y) {} /* unused vars warning: */
1882
if (last < 0 || which != last) {
1883
set_rfb_cursor(which);
1888
return changed_cursor;
1892
* routine called periodically to update cursor aspects, this catches
1893
* warps and cursor shape changes.
1895
int check_x11_pointer(void) {
1896
Window root_w, child_w;
1898
int root_x, root_y, win_x, win_y;
1902
if (unixpw_in_progress) return 0;
1905
if (macosx_console) {
1906
ret = macosx_get_cursor_pos(&root_x, &root_y);
1924
ret = XQueryPointer_wr(dpy, rootwin, &root_w, &child_w, &root_x, &root_y,
1925
&win_x, &win_y, &mask);
1929
if (!mask || !win_y || !win_x || !child_w || !root_w) {}
1932
if (0) fprintf(stderr, "check_x11_pointer %d %d\n", root_x, root_y);
1936
if (debug_pointer) {
1937
static int last_x = -1, last_y = -1;
1938
if (root_x != last_x || root_y != last_y) {
1939
rfbLog("XQueryPointer: x:%4d, y:%4d)\n",
1946
/* offset subtracted since XQueryPointer relative to rootwin */
1947
x = root_x - off_x - coff_x;
1948
y = root_y - off_y - coff_y;
1952
if (x < 0 || y < 0 || x >= dpy_x || y >= dpy_y) {
1953
if (cnt++ % 4 != 0) {
1954
if (debug_pointer) {
1955
rfbLog("Skipping cursor_position() outside our clipshift\n");
1962
/* record the cursor position in the rfb screen */
1963
cursor_position(x, y);
1965
/* change the cursor shape if necessary */
1966
return set_cursor(x, y, get_which_cursor());