summaryrefslogtreecommitdiffstats
path: root/x11vnc/cursor.c
diff options
context:
space:
mode:
authorrunge <runge>2006-01-09 01:54:38 +0000
committerrunge <runge>2006-01-09 01:54:38 +0000
commit71f2ec79180185a6c3db0c87f9d53c491dc31e76 (patch)
tree67c341571cbeb1bd9a0744cc8eb03b30ef04f381 /x11vnc/cursor.c
parentdef301266373e462f4a5e90eab443087ccfc7ccc (diff)
downloadlibtdevnc-71f2ec79180185a6c3db0c87f9d53c491dc31e76.tar.gz
libtdevnc-71f2ec79180185a6c3db0c87f9d53c491dc31e76.zip
x11vnc: the big split.
Diffstat (limited to 'x11vnc/cursor.c')
-rw-r--r--x11vnc/cursor.c1786
1 files changed, 1786 insertions, 0 deletions
diff --git a/x11vnc/cursor.c b/x11vnc/cursor.c
new file mode 100644
index 0000000..4c8cca7
--- /dev/null
+++ b/x11vnc/cursor.c
@@ -0,0 +1,1786 @@
+/* -- cursor.c -- */
+
+#include "x11vnc.h"
+#include "xwrappers.h"
+#include "cleanup.h"
+#include "screen.h"
+#include "scan.h"
+
+int xfixes_present = 0;
+int use_xfixes = 1;
+int got_xfixes_cursor_notify = 0;
+int cursor_changes = 0;
+int alpha_threshold = 240;
+double alpha_frac = 0.33;
+int alpha_remove = 0;
+int alpha_blend = 1;
+int alt_arrow = 1;
+
+
+void first_cursor(void);
+void setup_cursors_and_push(void);
+void initialize_xfixes(void);
+int known_cursors_mode(char *s);
+void initialize_cursors_mode(void);
+int get_which_cursor(void);
+void restore_cursor_shape_updates(rfbScreenInfoPtr s);
+void disable_cursor_shape_updates(rfbScreenInfoPtr s);
+int cursor_shape_updates_clients(rfbScreenInfoPtr s);
+int cursor_pos_updates_clients(rfbScreenInfoPtr s);
+void cursor_position(int x, int y);
+void set_no_cursor(void);
+int set_cursor(int x, int y, int which);
+int check_x11_pointer(void);
+
+
+typedef struct win_str_info {
+ char *wm_name;
+ char *res_name;
+ char *res_class;
+} win_str_info_t;
+
+typedef struct cursor_info {
+ char *data; /* data and mask pointers */
+ char *mask;
+ int wx, wy; /* size of cursor */
+ int sx, sy; /* shift to its centering point */
+ int reverse; /* swap black and white */
+ rfbCursorPtr rfb;
+} cursor_info_t;
+
+
+static void curs_copy(cursor_info_t *dest, cursor_info_t *src);
+static void setup_cursors(void);
+static void set_rfb_cursor(int which);
+static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo);
+static rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h,
+ int xhot, int yhot, int Bpp);
+static int get_xfixes_cursor(int init);
+static void set_cursor_was_changed(rfbScreenInfoPtr s);
+
+
+/*
+ * Here begins a bit of a mess to experiment with multiple cursors
+ * drawn on the remote background ...
+ */
+static void curs_copy(cursor_info_t *dest, cursor_info_t *src) {
+ if (src->data != NULL) {
+ dest->data = strdup(src->data);
+ } else {
+ dest->data = NULL;
+ }
+ if (src->mask != NULL) {
+ dest->mask = strdup(src->mask);
+ } else {
+ dest->mask = NULL;
+ }
+ dest->wx = src->wx;
+ dest->wy = src->wy;
+ dest->sx = src->sx;
+ dest->sy = src->sy;
+ dest->reverse = src->reverse;
+ dest->rfb = src->rfb;
+}
+
+/* empty cursor */
+static char* curs_empty_data =
+" "
+" ";
+
+static char* curs_empty_mask =
+" "
+" ";
+static cursor_info_t cur_empty = {NULL, NULL, 2, 2, 0, 0, 0, NULL};
+
+/* dot cursor */
+static char* curs_dot_data =
+" "
+" x";
+
+static char* curs_dot_mask =
+" "
+" x";
+static cursor_info_t cur_dot = {NULL, NULL, 2, 2, 0, 0, 0, NULL};
+
+
+/* main cursor */
+static char* curs_arrow_data =
+" "
+" x "
+" xx "
+" xxx "
+" xxxx "
+" xxxxx "
+" xxxxxx "
+" xxxxxxx "
+" xxxxxxxx "
+" xxxxx "
+" xx xx "
+" x xx "
+" xx "
+" xx "
+" xx "
+" "
+" "
+" ";
+
+static char* curs_arrow_mask =
+"xx "
+"xxx "
+"xxxx "
+"xxxxx "
+"xxxxxx "
+"xxxxxxx "
+"xxxxxxxx "
+"xxxxxxxxx "
+"xxxxxxxxxx "
+"xxxxxxxxxx "
+"xxxxxxx "
+"xxx xxxx "
+"xx xxxx "
+" xxxx "
+" xxxx "
+" xx "
+" "
+" ";
+static cursor_info_t cur_arrow = {NULL, NULL, 18, 18, 0, 0, 1, NULL};
+
+static char* curs_arrow2_data =
+" "
+" x "
+" xx "
+" xxx "
+" xxxx "
+" xxxxx "
+" xxxxxx "
+" xxxxxxx "
+" xxxxxxxx "
+" xxxxx "
+" xx xx "
+" x xx "
+" xx "
+" xx "
+" xx "
+" "
+" "
+" ";
+
+static char* curs_arrow2_mask =
+"xx "
+"xxx "
+"xxxx "
+"xxxxx "
+"xxxxxx "
+"xxxxxxx "
+"xxxxxxxx "
+"xxxxxxxxx "
+"xxxxxxxxxx "
+"xxxxxxxxxx "
+"xxxxxxx "
+"xxx xxxx "
+"xx xxxx "
+" xxxx "
+" xxxx "
+" xx "
+" "
+" ";
+static cursor_info_t cur_arrow2 = {NULL, NULL, 18, 18, 0, 0, 0, NULL};
+
+static char* curs_arrow3_data =
+" "
+" xx "
+" xxxx "
+" xxxxx "
+" xxxxxxx "
+" xxxxxxxx "
+" xxxxxxxxxx "
+" xxxxx "
+" xxxxx "
+" xx x "
+" xx x "
+" x x "
+" x x "
+" x "
+" x "
+" ";
+
+static char* curs_arrow3_mask =
+"xxx "
+"xxxxx "
+"xxxxxxx "
+" xxxxxxxx "
+" xxxxxxxxxx "
+" xxxxxxxxxxxx "
+" xxxxxxxxxxxx "
+" xxxxxxxxxxx "
+" xxxxxxx "
+" xxxxxxx "
+" xxxx xxx "
+" xxx xxx "
+" xxx xxx "
+" xxx xxx "
+" xxx"
+" xx";
+
+static cursor_info_t cur_arrow3 = {NULL, NULL, 16, 16, 0, 0, 1, NULL};
+
+static char* curs_arrow4_data =
+" "
+" xx "
+" xxxx "
+" xxxxx "
+" xxxxxxx "
+" xxxxxxxx "
+" xxxxxxxxxx "
+" xxxxx "
+" xxxxx "
+" xx x "
+" xx x "
+" x x "
+" x x "
+" x "
+" x "
+" ";
+
+static char* curs_arrow4_mask =
+"xxx "
+"xxxxx "
+"xxxxxxx "
+" xxxxxxxx "
+" xxxxxxxxxx "
+" xxxxxxxxxxxx "
+" xxxxxxxxxxxx "
+" xxxxxxxxxxx "
+" xxxxxxx "
+" xxxxxxx "
+" xxxx xxx "
+" xxx xxx "
+" xxx xxx "
+" xxx xxx "
+" xxx"
+" xx";
+
+static cursor_info_t cur_arrow4 = {NULL, NULL, 16, 16, 0, 0, 0, NULL};
+
+static char* curs_arrow5_data =
+"x "
+" xx "
+" xxxx "
+" xxxxx "
+" xxxxxxx "
+" xxx "
+" xx x "
+" x x "
+" x x "
+" x "
+" x "
+" x "
+" x "
+" x "
+" x";
+
+static char* curs_arrow5_mask =
+"xx "
+"xxxx "
+" xxxxx "
+" xxxxxxx "
+" xxxxxxxx "
+" xxxxxxxx "
+" xxxxx "
+" xxxxxx "
+" xx xxx "
+" x xxx "
+" xxx "
+" xxx "
+" xxx "
+" xxx"
+" xx";
+
+static cursor_info_t cur_arrow5 = {NULL, NULL, 15, 15, 0, 0, 1, NULL};
+
+static char* curs_arrow6_data =
+"x "
+" xx "
+" xxxx "
+" xxxxx "
+" xxxxxxx "
+" xxx "
+" xx x "
+" x x "
+" x x "
+" x "
+" x "
+" x "
+" x "
+" x "
+" x";
+
+static char* curs_arrow6_mask =
+"xx "
+"xxxx "
+" xxxxx "
+" xxxxxxx "
+" xxxxxxxx "
+" xxxxxxxx "
+" xxxxx "
+" xxxxxx "
+" xx xxx "
+" x xxx "
+" xxx "
+" xxx "
+" xxx "
+" xxx"
+" xx";
+
+static cursor_info_t cur_arrow6 = {NULL, NULL, 15, 15, 0, 0, 0, NULL};
+
+int alt_arrow_max = 6;
+/*
+ * It turns out we can at least detect mouse is on the root window so
+ * show it (under -cursor X) with this familiar cursor...
+ */
+static char* curs_root_data =
+" "
+" "
+" xxx xxx "
+" xxxx xxxx "
+" xxxxx xxxxx "
+" xxxxx xxxxx "
+" xxxxxxxxxx "
+" xxxxxxxx "
+" xxxxxx "
+" xxxxxx "
+" xxxxxxxx "
+" xxxxxxxxxx "
+" xxxxx xxxxx "
+" xxxxx xxxxx "
+" xxxx xxxx "
+" xxx xxx "
+" "
+" ";
+
+static char* curs_root_mask =
+" "
+" xxxx xxxx "
+" xxxxx xxxxx "
+" xxxxxx xxxxxx "
+" xxxxxxx xxxxxxx "
+" xxxxxxxxxxxxxx "
+" xxxxxxxxxxxx "
+" xxxxxxxxxx "
+" xxxxxxxx "
+" xxxxxxxx "
+" xxxxxxxxxx "
+" xxxxxxxxxxxx "
+" xxxxxxxxxxxxxx "
+" xxxxxxx xxxxxxx "
+" xxxxxx xxxxxx "
+" xxxxx xxxxx "
+" xxxx xxxx "
+" ";
+static cursor_info_t cur_root = {NULL, NULL, 18, 18, 8, 8, 1, NULL};
+
+static char* curs_fleur_data =
+" "
+" xx "
+" xxxx "
+" xxxxxx "
+" xx "
+" x xx x "
+" xx xx xx "
+" xxxxxxxxxxxxxx "
+" xxxxxxxxxxxxxx "
+" xx xx xx "
+" x xx x "
+" xx "
+" xxxxxx "
+" xxxx "
+" xx "
+" ";
+
+static char* curs_fleur_mask =
+" xxxx "
+" xxxxx "
+" xxxxxx "
+" xxxxxxxx "
+" x xxxxxx x "
+" xxx xxxx xxx "
+"xxxxxxxxxxxxxxxx"
+"xxxxxxxxxxxxxxxx"
+"xxxxxxxxxxxxxxxx"
+"xxxxxxxxxxxxxxxx"
+" xxx xxxx xxx "
+" x xxxxxx x "
+" xxxxxxxx "
+" xxxxxx "
+" xxxx "
+" xxxx ";
+
+static cursor_info_t cur_fleur = {NULL, NULL, 16, 16, 8, 8, 1, NULL};
+
+static char* curs_plus_data =
+" "
+" xx "
+" xx "
+" xx "
+" xx "
+" xxxxxxxxxx "
+" xxxxxxxxxx "
+" xx "
+" xx "
+" xx "
+" xx "
+" ";
+
+static char* curs_plus_mask =
+" xxxx "
+" xxxx "
+" xxxx "
+" xxxx "
+"xxxxxxxxxxxx"
+"xxxxxxxxxxxx"
+"xxxxxxxxxxxx"
+"xxxxxxxxxxxx"
+" xxxx "
+" xxxx "
+" xxxx "
+" xxxx ";
+static cursor_info_t cur_plus = {NULL, NULL, 12, 12, 5, 6, 1, NULL};
+
+static char* curs_xterm_data =
+" "
+" xxx xxx "
+" xxx "
+" x "
+" x "
+" x "
+" x "
+" x "
+" x "
+" x "
+" x "
+" x "
+" x "
+" xxx "
+" xxx xxx "
+" ";
+
+static char* curs_xterm_mask =
+" xxxx xxxx "
+" xxxxxxxxx "
+" xxxxxxxxx "
+" xxxxx "
+" xxx "
+" xxx "
+" xxx "
+" xxx "
+" xxx "
+" xxx "
+" xxx "
+" xxx "
+" xxxxx "
+" xxxxxxxxx "
+" xxxxxxxxx "
+" xxxx xxxx ";
+static cursor_info_t cur_xterm = {NULL, NULL, 16, 16, 8, 8, 1, NULL};
+
+enum cursor_names {
+ CURS_EMPTY = 0,
+ CURS_DOT,
+
+ CURS_ARROW,
+ CURS_ROOT,
+ CURS_WM,
+ CURS_TERM,
+ CURS_PLUS,
+
+ CURS_DYN1,
+ CURS_DYN2,
+ CURS_DYN3,
+ CURS_DYN4,
+ CURS_DYN5,
+ CURS_DYN6,
+ CURS_DYN7,
+ CURS_DYN8,
+ CURS_DYN9,
+ CURS_DYN10,
+ CURS_DYN11,
+ CURS_DYN12,
+ CURS_DYN13,
+ CURS_DYN14,
+ CURS_DYN15,
+ CURS_DYN16
+};
+
+#define CURS_DYN_MIN CURS_DYN1
+#define CURS_DYN_MAX CURS_DYN16
+#define CURS_DYN_NUM (CURS_DYN_MAX - CURS_DYN_MIN + 1)
+
+#define CURS_MAX 32
+static cursor_info_t *cursors[CURS_MAX];
+
+void first_cursor(void) {
+ if (! screen) {
+ return;
+ }
+ if (! show_cursor) {
+ screen->cursor = NULL;
+ } else {
+ got_xfixes_cursor_notify++;
+ set_rfb_cursor(get_which_cursor());
+ set_cursor_was_changed(screen);
+ }
+}
+
+static void setup_cursors(void) {
+ rfbCursorPtr rfb_curs;
+ char *scale = NULL;
+ int i, j, n = 0;
+ static int first = 1;
+
+ rfbLog("setting up %d cursors...\n", CURS_MAX);
+
+ if (first) {
+ for (i=0; i<CURS_MAX; i++) {
+ cursors[i] = NULL;
+ }
+ }
+ first = 0;
+
+ if (screen) {
+ screen->cursor = NULL;
+ LOCK(screen->cursorMutex);
+ }
+
+ for (i=0; i<CURS_MAX; i++) {
+ cursor_info_t *ci;
+ if (cursors[i]) {
+ /* clear out any existing ones: */
+ ci = cursors[i];
+ if (ci->rfb) {
+ /* this is the rfbCursor part: */
+ if (ci->rfb->richSource) {
+ free(ci->rfb->richSource);
+ ci->rfb->richSource = NULL;
+ }
+ if (ci->rfb->source) {
+ free(ci->rfb->source);
+ ci->rfb->source = NULL;
+ }
+ if (ci->rfb->mask) {
+ free(ci->rfb->mask);
+ ci->rfb->mask = NULL;
+ }
+ free(ci->rfb);
+ ci->rfb = NULL;
+ }
+ if (ci->data) {
+ free(ci->data);
+ ci->data = NULL;
+ }
+ if (ci->mask) {
+ free(ci->mask);
+ ci->mask = NULL;
+ }
+ free(ci);
+ ci = NULL;
+ }
+
+ /* create new struct: */
+ ci = (cursor_info_t *) malloc(sizeof(cursor_info_t));
+ ci->data = NULL;
+ ci->mask = NULL;
+ ci->wx = 0;
+ ci->wy = 0;
+ ci->sx = 0;
+ ci->sy = 0;
+ ci->reverse = 0;
+ ci->rfb = NULL;
+ cursors[i] = ci;
+ }
+
+ /* clear any xfixes cursor cache (no freeing is done) */
+ get_xfixes_cursor(1);
+
+ /* manually fill in the data+masks: */
+ cur_empty.data = curs_empty_data;
+ cur_empty.mask = curs_empty_mask;
+
+ cur_dot.data = curs_dot_data;
+ cur_dot.mask = curs_dot_mask;
+
+ cur_arrow.data = curs_arrow_data;
+ cur_arrow.mask = curs_arrow_mask;
+ cur_arrow2.data = curs_arrow2_data;
+ cur_arrow2.mask = curs_arrow2_mask;
+ cur_arrow3.data = curs_arrow3_data;
+ cur_arrow3.mask = curs_arrow3_mask;
+ cur_arrow4.data = curs_arrow4_data;
+ cur_arrow4.mask = curs_arrow4_mask;
+ cur_arrow5.data = curs_arrow5_data;
+ cur_arrow5.mask = curs_arrow5_mask;
+ cur_arrow6.data = curs_arrow6_data;
+ cur_arrow6.mask = curs_arrow6_mask;
+
+ cur_root.data = curs_root_data;
+ cur_root.mask = curs_root_mask;
+
+ cur_plus.data = curs_plus_data;
+ cur_plus.mask = curs_plus_mask;
+
+ cur_fleur.data = curs_fleur_data;
+ cur_fleur.mask = curs_fleur_mask;
+
+ cur_xterm.data = curs_xterm_data;
+ cur_xterm.mask = curs_xterm_mask;
+
+ curs_copy(cursors[CURS_EMPTY], &cur_empty); n++;
+ curs_copy(cursors[CURS_DOT], &cur_dot); n++;
+
+ if (alt_arrow < 1 || alt_arrow > alt_arrow_max) {
+ alt_arrow = 1;
+ }
+ if (alt_arrow == 1) {
+ curs_copy(cursors[CURS_ARROW], &cur_arrow); n++;
+ } else if (alt_arrow == 2) {
+ curs_copy(cursors[CURS_ARROW], &cur_arrow2); n++;
+ } else if (alt_arrow == 3) {
+ curs_copy(cursors[CURS_ARROW], &cur_arrow3); n++;
+ } else if (alt_arrow == 4) {
+ curs_copy(cursors[CURS_ARROW], &cur_arrow4); n++;
+ } else if (alt_arrow == 5) {
+ curs_copy(cursors[CURS_ARROW], &cur_arrow5); n++;
+ } else if (alt_arrow == 6) {
+ curs_copy(cursors[CURS_ARROW], &cur_arrow6); n++;
+ } else {
+ alt_arrow = 1;
+ curs_copy(cursors[CURS_ARROW], &cur_arrow); n++;
+ }
+
+ curs_copy(cursors[CURS_ROOT], &cur_root); n++;
+ curs_copy(cursors[CURS_WM], &cur_fleur); n++;
+ curs_copy(cursors[CURS_TERM], &cur_xterm); n++;
+ curs_copy(cursors[CURS_PLUS], &cur_plus); n++;
+
+ if (scale_cursor_str) {
+ scale = scale_cursor_str;
+ } else if (scaling && scale_str) {
+ scale = scale_str;
+ }
+ /* scale = NULL zeroes everything */
+ parse_scale_string(scale, &scale_cursor_fac, &scaling_cursor,
+ &scaling_cursor_blend, &j, &j, &scaling_cursor_interpolate,
+ &scale_cursor_numer, &scale_cursor_denom);
+
+ for (i=0; i<n; i++) {
+ /* create rfbCursors for the special cursors: */
+
+ cursor_info_t *ci = cursors[i];
+
+ if (scaling_cursor && scale_cursor_fac != 1.0) {
+ int w, h, x, y, k;
+ unsigned long *pixels;
+
+ w = ci->wx;
+ h = ci->wy;
+
+ pixels = (unsigned long *) malloc(w * h
+ * sizeof(unsigned long));
+
+ k = 0;
+ for (y=0; y<h; y++) {
+ for (x=0; x<w; x++) {
+ char d = ci->data[k];
+ char m = ci->mask[k];
+ unsigned long *p;
+
+ p = pixels + k;
+
+ /* set alpha on */
+ *p = 0xff000000;
+
+ if (d == ' ' && m == ' ') {
+ /* alpha off */
+ *p = 0x00000000;
+ } else if (d != ' ') {
+ /* body */
+ if (ci->reverse) {
+ *p |= 0x00000000;
+ } else {
+ *p |= 0x00ffffff;
+ }
+ } else if (m != ' ') {
+ /* edge */
+ if (ci->reverse) {
+ *p |= 0x00ffffff;
+ } else {
+ *p |= 0x00000000;
+ }
+ }
+ k++;
+ }
+ }
+
+ rfb_curs = pixels2curs(pixels, w, h, ci->sx, ci->sy,
+ bpp/8);
+
+ free(pixels);
+
+ } else {
+
+ /* standard X cursor */
+ rfb_curs = rfbMakeXCursor(ci->wx, ci->wy,
+ ci->data, ci->mask);
+
+ if (ci->reverse) {
+ rfb_curs->foreRed = 0x0000;
+ rfb_curs->foreGreen = 0x0000;
+ rfb_curs->foreBlue = 0x0000;
+ rfb_curs->backRed = 0xffff;
+ rfb_curs->backGreen = 0xffff;
+ rfb_curs->backBlue = 0xffff;
+ }
+ rfb_curs->alphaSource = NULL;
+
+ rfb_curs->xhot = ci->sx;
+ rfb_curs->yhot = ci->sy;
+ rfb_curs->cleanup = FALSE;
+ rfb_curs->cleanupSource = FALSE;
+ rfb_curs->cleanupMask = FALSE;
+ rfb_curs->cleanupRichSource = FALSE;
+
+ if (bpp == 8 && indexed_color) {
+ /*
+ * use richsource in PseudoColor for better
+ * looking cursors (i.e. two-color).
+ */
+ int x, y, k = 0, bw;
+ int black = 0, white = 1;
+ char d, m;
+
+ if (dpy) { /* raw_fb hack */
+ black = BlackPixel(dpy, scr);
+ white = WhitePixel(dpy, scr);
+ }
+
+ rfb_curs->richSource = (unsigned char *)
+ calloc(ci->wx * ci->wy, 1);
+
+ for (y = 0; y < ci->wy; y++) {
+ for (x = 0; x < ci->wx; x++) {
+ d = *(ci->data + k);
+ m = *(ci->mask + k);
+ if (d == ' ' && m == ' ') {
+ k++;
+ continue;
+ } else if (m != ' ' && d == ' ') {
+ bw = black;
+ } else {
+ bw = white;
+ }
+ if (ci->reverse) {
+ if (bw == black) {
+ bw = white;
+ } else {
+ bw = black;
+ }
+ }
+ *(rfb_curs->richSource+k) =
+ (unsigned char) bw;
+ k++;
+ }
+ }
+ }
+ }
+ ci->rfb = rfb_curs;
+ }
+ if (screen) {
+ UNLOCK(screen->cursorMutex);
+ }
+ rfbLog(" done.\n");
+}
+
+void setup_cursors_and_push(void) {
+ setup_cursors();
+ first_cursor();
+}
+
+/*
+ * Descends window tree at pointer until the window cursor matches the current
+ * cursor. So far only used to detect if mouse is on root background or not.
+ * (returns 0 in that case, 1 otherwise).
+ *
+ */
+static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
+ Window r, c;
+ int i, rx, ry, wx, wy;
+ unsigned int mask;
+ Window wins[10];
+ int descend, maxtries = 10;
+ char *name, *s = multiple_cursors_mode;
+ static XClassHint *classhint = NULL;
+ int nm_info = 1;
+ XErrorHandler old_handler;
+
+ X_LOCK;
+
+ if (!strcmp(s, "default") || !strcmp(s, "X") || !strcmp(s, "arrow")) {
+ nm_info = 0;
+ }
+
+ *(winfo->wm_name) = '\0';
+ *(winfo->res_name) = '\0';
+ *(winfo->res_class) = '\0';
+
+
+ /* some times a window can go away before we get to it */
+ trapped_xerror = 0;
+ old_handler = XSetErrorHandler(trap_xerror);
+
+ c = window;
+ descend = -1;
+
+ while (c) {
+ wins[++descend] = c;
+ if (descend >= maxtries - 1) {
+ break;
+ }
+ if ( XTestCompareCurrentCursorWithWindow_wr(dpy, c) ) {
+ break;
+ }
+ /* TBD: query_pointer() */
+ XQueryPointer(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &mask);
+ }
+
+ if (nm_info) {
+ int got_wm_name = 0, got_res_name = 0, got_res_class = 0;
+
+ if (! classhint) {
+ classhint = XAllocClassHint();
+ }
+
+ for (i = descend; i >=0; i--) {
+ c = wins[i];
+ if (! c) {
+ continue;
+ }
+
+ if (! got_wm_name && XFetchName(dpy, c, &name)) {
+ if (name) {
+ if (*name != '\0') {
+ strcpy(winfo->wm_name, name);
+ got_wm_name = 1;
+ }
+ XFree(name);
+ }
+ }
+ if (classhint && (! got_res_name || ! got_res_class)) {
+ if (XGetClassHint(dpy, c, classhint)) {
+ char *p;
+ p = classhint->res_name;
+ if (p) {
+ if (*p != '\0' && ! got_res_name) {
+ strcpy(winfo->res_name, p);
+ got_res_name = 1;
+ }
+ XFree(p);
+ classhint->res_name = NULL;
+ }
+ p = classhint->res_class;
+ if (p) {
+ if (*p != '\0' && ! got_res_class) {
+ strcpy(winfo->res_class, p);
+ got_res_class = 1;
+ }
+ XFree(p);
+ classhint->res_class = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ XSetErrorHandler(old_handler);
+ trapped_xerror = 0;
+
+ X_UNLOCK;
+
+ *depth = descend;
+ *w = wins[descend];
+}
+
+void initialize_xfixes(void) {
+#if LIBVNCSERVER_HAVE_LIBXFIXES
+ if (xfixes_present) {
+ X_LOCK;
+ if (use_xfixes) {
+ XFixesSelectCursorInput(dpy, rootwin,
+ XFixesDisplayCursorNotifyMask);
+ } else {
+ XFixesSelectCursorInput(dpy, rootwin, 0);
+ }
+ X_UNLOCK;
+ }
+#endif
+}
+
+static rfbCursorPtr pixels2curs(unsigned long *pixels, int w, int h,
+ int xhot, int yhot, int Bpp) {
+ rfbCursorPtr c;
+ static unsigned long black = 0, white = 1;
+ static int first = 1;
+ char *bitmap, *rich, *alpha;
+ char *pixels_new = NULL;
+ int n_opaque, n_trans, n_alpha, len, histo[256];
+ int send_alpha = 0, alpha_shift, thresh;
+ int i, x, y;
+
+ if (first && dpy) { /* raw_fb hack */
+ X_LOCK;
+ black = BlackPixel(dpy, scr);
+ white = WhitePixel(dpy, scr);
+ X_UNLOCK;
+ first = 0;
+ }
+
+ if (scaling_cursor && scale_cursor_fac != 1.0) {
+ int W, H;
+ char *pixels_use = (char *) pixels;
+ unsigned int *pixels32 = NULL;
+
+ W = w;
+ H = h;
+
+ w = scale_round(W, scale_cursor_fac);
+ h = scale_round(H, scale_cursor_fac);
+
+ pixels_new = (char *) malloc(4*w*h);
+
+ if (sizeof(unsigned long) == 8) {
+ int i, j, k = 0;
+ /*
+ * to avoid 64bpp code in scale_rect() we knock
+ * down to unsigned int on 64bit machines:
+ */
+ pixels32 = (unsigned int*) malloc(4*W*H);
+ for (j=0; j<H; j++) {
+ for (i=0; i<W; i++) {
+ *(pixels32+k) = 0xffffffff & (*(pixels+k));
+ k++;
+ }
+ }
+ pixels_use = (char *) pixels32;
+ }
+
+ scale_rect(scale_cursor_fac, scaling_cursor_blend,
+ scaling_cursor_interpolate,
+ 4, pixels_use, 4*W, pixels_new, 4*w,
+ W, H, w, h, 0, 0, W, H, 0);
+
+ if (sizeof(unsigned long) == 8) {
+ int i, j, k = 0;
+ unsigned long *pixels64;
+ unsigned int* source = (unsigned int*) pixels_new;
+ /*
+ * now knock it back up to unsigned long:
+ */
+ pixels64 = (unsigned long*) malloc(8*w*h);
+ for (j=0; j<h; j++) {
+ for (i=0; i<w; i++) {
+ *(pixels64+k) = (unsigned long) (*(source+k));
+ k++;
+ }
+ }
+ free(pixels_new);
+ pixels_new = (char *) pixels64;
+ if (pixels32) {
+ free(pixels32);
+ pixels32 = NULL;
+ }
+ }
+
+ pixels = (unsigned long *) pixels_new;
+
+ xhot = scale_round(xhot, scale_cursor_fac);
+ yhot = scale_round(yhot, scale_cursor_fac);
+ }
+
+ len = w * h;
+ /* for bitmap data */
+ bitmap = (char *) malloc(len+1);
+ bitmap[len] = '\0';
+
+ /* for rich cursor pixel data */
+ rich = (char *)calloc(Bpp*len, 1);
+ alpha = (char *)calloc(1*len, 1);
+
+ n_opaque = 0;
+ n_trans = 0;
+ n_alpha = 0;
+ for (i=0; i<256; i++) {
+ histo[i] = 0;
+ }
+
+ i = 0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ unsigned long a;
+
+ a = 0xff000000 & (*(pixels+i));
+ a = a >> 24; /* alpha channel */
+ if (a > 0) {
+ n_alpha++;
+ }
+ histo[a]++;
+ if (a < (unsigned int) alpha_threshold) {
+ n_trans++;
+ } else {
+ n_opaque++;
+ }
+ i++;
+ }
+ }
+ if (alpha_blend) {
+ send_alpha = 0;
+ if (Bpp == 4) {
+ send_alpha = 1;
+ }
+ alpha_shift = 24;
+ if (main_red_shift == 24 || main_green_shift == 24 ||
+ main_blue_shift == 24) {
+ alpha_shift = 0; /* XXX correct? */
+ }
+ }
+ if (n_opaque >= alpha_frac * n_alpha) {
+ thresh = alpha_threshold;
+ } else {
+ n_opaque = 0;
+ for (i=255; i>=0; i--) {
+ n_opaque += histo[i];
+ thresh = i;
+ if (n_opaque >= alpha_frac * n_alpha) {
+ break;
+ }
+ }
+ }
+
+ i = 0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ unsigned long r, g, b, a;
+ unsigned int ui;
+ char *p;
+
+ a = 0xff000000 & (*(pixels+i));
+ a = a >> 24; /* alpha channel */
+
+
+ if (a < (unsigned int) thresh) {
+ bitmap[i] = ' ';
+ } else {
+ bitmap[i] = 'x';
+ }
+
+ r = 0x00ff0000 & (*(pixels+i));
+ g = 0x0000ff00 & (*(pixels+i));
+ b = 0x000000ff & (*(pixels+i));
+ r = r >> 16; /* red */
+ g = g >> 8; /* green */
+ b = b >> 0; /* blue */
+
+ if (alpha_remove && a != 0) {
+ r = (255 * r) / a;
+ g = (255 * g) / a;
+ b = (255 * b) / a;
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+ }
+
+ if (indexed_color) {
+ /*
+ * Choose black or white for
+ * PseudoColor case.
+ */
+ int value = (r+g+b)/3;
+ if (value > 127) {
+ ui = white;
+ } else {
+ ui = black;
+ }
+ } else {
+ /*
+ * Otherwise map the RGB data onto
+ * the framebuffer format:
+ */
+ r = (main_red_max * r)/255;
+ g = (main_green_max * g)/255;
+ b = (main_blue_max * b)/255;
+ ui = 0;
+ ui |= (r << main_red_shift);
+ ui |= (g << main_green_shift);
+ ui |= (b << main_blue_shift);
+ if (send_alpha) {
+ ui |= (a << alpha_shift);
+ }
+ }
+
+ /* insert value into rich source: */
+ p = rich + Bpp*i;
+
+ if (Bpp == 1) {
+ *((unsigned char *)p)
+ = (unsigned char) ui;
+ } else if (Bpp == 2) {
+ *((unsigned short *)p)
+ = (unsigned short) ui;
+ } else if (Bpp == 3) {
+ *((unsigned char *)p)
+ = (unsigned char) ((ui & 0x0000ff) >> 0);
+ *((unsigned char *)(p+1))
+ = (unsigned char) ((ui & 0x00ff00) >> 8);
+ *((unsigned char *)(p+2))
+ = (unsigned char) ((ui & 0xff0000) >> 16);
+ } else if (Bpp == 4) {
+ *((unsigned int *)p)
+ = (unsigned int) ui;
+ }
+
+ /* insert alpha value into alpha source: */
+ p = alpha + i;
+ *((unsigned char *)p) = (unsigned char) a;
+
+ i++;
+ }
+ }
+
+ /* create the cursor with the bitmap: */
+ c = rfbMakeXCursor(w, h, bitmap, bitmap);
+ free(bitmap);
+
+ if (pixels_new) {
+ free(pixels_new);
+ }
+
+ /* set up the cursor parameters: */
+ c->xhot = xhot;
+ c->yhot = yhot;
+ c->cleanup = FALSE;
+ c->cleanupSource = FALSE;
+ c->cleanupMask = FALSE;
+ c->cleanupRichSource = FALSE;
+ c->richSource = (unsigned char *) rich;
+
+ if (alpha_blend && !indexed_color) {
+ c->alphaSource = (unsigned char *) alpha;
+ c->alphaPreMultiplied = TRUE;
+ } else {
+ free(alpha);
+ c->alphaSource = NULL;
+ }
+ return c;
+}
+
+static int get_xfixes_cursor(int init) {
+ static unsigned long last_cursor = 0;
+ static int last_index = 0;
+ static time_t curs_times[CURS_MAX];
+ static unsigned long curs_index[CURS_MAX];
+ int which = CURS_ARROW;
+
+ if (init) {
+ /* zero out our cache (cursors are not freed) */
+ int i;
+ for (i=0; i<CURS_MAX; i++) {
+ curs_times[i] = 0;
+ curs_index[i] = 0;
+ }
+ last_cursor = 0;
+ last_index = 0;
+ return -1;
+ }
+
+ if (xfixes_present) {
+#if LIBVNCSERVER_HAVE_LIBXFIXES
+ int use, oldest, i;
+ time_t oldtime, now;
+ XFixesCursorImage *xfc;
+
+ if (! got_xfixes_cursor_notify && xfixes_base_event_type) {
+ /* try again for XFixesCursorNotify event */
+ XEvent xev;
+ X_LOCK;
+ if (XCheckTypedEvent(dpy, xfixes_base_event_type +
+ XFixesCursorNotify, &xev)) {
+ got_xfixes_cursor_notify++;
+ }
+ X_UNLOCK;
+ }
+ if (! got_xfixes_cursor_notify) {
+ /* evidently no cursor change, just return last one */
+ if (last_index) {
+ return last_index;
+ } else {
+ return CURS_ARROW;
+ }
+ }
+ got_xfixes_cursor_notify = 0;
+
+ /* retrieve the cursor info + pixels from server: */
+ X_LOCK;
+ xfc = XFixesGetCursorImage(dpy);
+ X_UNLOCK;
+ if (! xfc) {
+ /* failure. */
+ return(which);
+ }
+
+ if (xfc->cursor_serial == last_cursor) {
+ /* same serial index: no change */
+ X_LOCK;
+ XFree(xfc);
+ X_UNLOCK;
+ if (last_index) {
+ return last_index;
+ } else {
+ return CURS_ARROW;
+ }
+ }
+
+ oldest = CURS_DYN_MIN;
+ if (screen && screen->cursor == cursors[oldest]->rfb) {
+ oldest++;
+ }
+ oldtime = curs_times[oldest];
+ now = time(0);
+ for (i = CURS_DYN_MIN; i <= CURS_DYN_MAX; i++) {
+ if (screen && screen->cursor == cursors[i]->rfb) {
+ ;
+ } else if (curs_times[i] < oldtime) {
+ /* watch for oldest one to overwrite */
+ oldest = i;
+ oldtime = curs_times[i];
+ }
+ if (xfc->cursor_serial == curs_index[i]) {
+ /*
+ * got a hit with an existing cursor,
+ * use that one.
+ */
+ last_cursor = curs_index[i];
+ curs_times[i] = now;
+ last_index = i;
+ X_LOCK;
+ XFree(xfc);
+ X_UNLOCK;
+ return last_index;
+ }
+ }
+
+ /* we need to create the cursor and overwrite oldest */
+ use = oldest;
+ if (cursors[use]->rfb) {
+ /* clean up oldest if it exists */
+ if (cursors[use]->rfb->richSource) {
+ free(cursors[use]->rfb->richSource);
+ cursors[use]->rfb->richSource = NULL;
+ }
+ if (cursors[use]->rfb->alphaSource) {
+ free(cursors[use]->rfb->alphaSource);
+ cursors[use]->rfb->alphaSource = NULL;
+ }
+ if (cursors[use]->rfb->source) {
+ free(cursors[use]->rfb->source);
+ cursors[use]->rfb->source = NULL;
+ }
+ if (cursors[use]->rfb->mask) {
+ free(cursors[use]->rfb->mask);
+ cursors[use]->rfb->mask = NULL;
+ }
+ free(cursors[use]->rfb);
+ cursors[use]->rfb = NULL;
+ }
+
+ /* place cursor into our collection */
+ cursors[use]->rfb = pixels2curs(xfc->pixels, xfc->width,
+ xfc->height, xfc->xhot, xfc->yhot, bpp/8);
+
+ /* update time and serial index: */
+ curs_times[use] = now;
+ curs_index[use] = xfc->cursor_serial;
+ last_index = use;
+ last_cursor = xfc->cursor_serial;
+
+ which = last_index;
+
+ X_LOCK;
+ XFree(xfc);
+ X_UNLOCK;
+#endif
+ }
+ return(which);
+}
+
+int known_cursors_mode(char *s) {
+/*
+ * default: see initialize_cursors_mode() for default behavior.
+ * arrow: unchanging white arrow.
+ * Xn*: show X on root background. Optional n sets treedepth.
+ * some: do the heuristics for root, wm, term detection.
+ * most: if display have overlay or xfixes, show all cursors,
+ * otherwise do the same as "some"
+ * none: show no cursor.
+ */
+ if (strcmp(s, "default") && strcmp(s, "arrow") && *s != 'X' &&
+ strcmp(s, "some") && strcmp(s, "most") && strcmp(s, "none")) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+void initialize_cursors_mode(void) {
+ char *s = multiple_cursors_mode;
+ if (!s || !known_cursors_mode(s)) {
+ rfbLog("unknown cursors mode: %s\n", s);
+ rfbLog("resetting cursors mode to \"default\"\n");
+ if (multiple_cursors_mode) free(multiple_cursors_mode);
+ multiple_cursors_mode = strdup("default");
+ s = multiple_cursors_mode;
+ }
+ if (!strcmp(s, "none")) {
+ show_cursor = 0;
+ } else {
+ /* we do NOT set show_cursor = 1, let the caller do that */
+ }
+
+ show_multiple_cursors = 0;
+ if (show_cursor) {
+ if (!strcmp(s, "default")) {
+ if(multiple_cursors_mode) free(multiple_cursors_mode);
+ multiple_cursors_mode = strdup("X");
+ s = multiple_cursors_mode;
+ }
+ if (*s == 'X' || !strcmp(s, "some") || !strcmp(s, "most")) {
+ show_multiple_cursors = 1;
+ } else {
+ show_multiple_cursors = 0;
+ /* hmmm, some bug going back to arrow mode.. */
+ set_rfb_cursor(CURS_ARROW);
+ }
+ if (screen) {
+ set_cursor_was_changed(screen);
+ }
+ } else {
+ if (screen) {
+ screen->cursor = NULL; /* dangerous? */
+ set_cursor_was_changed(screen);
+ }
+ }
+}
+
+int get_which_cursor(void) {
+ int which = CURS_ARROW;
+
+ if (show_multiple_cursors) {
+ int depth;
+ static win_str_info_t winfo;
+ static int first = 1, depth_cutoff = -1;
+ Window win;
+ XErrorHandler old_handler;
+ int mode = 0;
+
+ if (drag_in_progress || button_mask) {
+ /* XXX not exactly what we want for menus */
+ return -1;
+ }
+
+ if (!strcmp(multiple_cursors_mode, "arrow")) {
+ /* should not happen... */
+ return CURS_ARROW;
+ } else if (!strcmp(multiple_cursors_mode, "default")) {
+ mode = 0;
+ } else if (!strcmp(multiple_cursors_mode, "X")) {
+ mode = 1;
+ } else if (!strcmp(multiple_cursors_mode, "some")) {
+ mode = 2;
+ } else if (!strcmp(multiple_cursors_mode, "most")) {
+ mode = 3;
+ }
+
+ if (mode == 3 && xfixes_present && use_xfixes) {
+ return get_xfixes_cursor(0);
+ }
+
+ if (depth_cutoff < 0) {
+ int din;
+ if (sscanf(multiple_cursors_mode, "X%d", &din) == 1) {
+ depth_cutoff = din;
+ } else {
+ depth_cutoff = 0;
+ }
+ }
+
+ if (first) {
+ winfo.wm_name = (char *) malloc(1024);
+ winfo.res_name = (char *) malloc(1024);
+ winfo.res_class = (char *) malloc(1024);
+ }
+ first = 0;
+
+ tree_descend_cursor(&depth, &win, &winfo);
+
+ if (depth <= depth_cutoff && !subwin) {
+ which = CURS_ROOT;
+
+ } else if (mode == 2 || mode == 3) {
+ int which0 = which;
+
+ /* apply crude heuristics to choose a cursor... */
+ if (win) {
+ int ratio = 10, x, y;
+ unsigned int w, h, bw, d;
+ Window r;
+
+ trapped_xerror = 0;
+ X_LOCK;
+ old_handler = XSetErrorHandler(trap_xerror);
+
+ /* "narrow" windows are WM */
+ if (XGetGeometry(dpy, win, &r, &x, &y, &w, &h,
+ &bw, &d)) {
+ if (w > ratio * h || h > ratio * w) {
+ which = CURS_WM;
+ }
+ }
+ XSetErrorHandler(old_handler);
+ X_UNLOCK;
+ trapped_xerror = 0;
+ }
+ if (which == which0) {
+ /* the string "term" mean I-beam. */
+ char *name, *class;
+ lowercase(winfo.res_name);
+ lowercase(winfo.res_class);
+ name = winfo.res_name;
+ class = winfo.res_class;
+ if (strstr(name, "term")) {
+ which = CURS_TERM;
+ } else if (strstr(class, "term")) {
+ which = CURS_TERM;
+ } else if (strstr(name, "text")) {
+ which = CURS_TERM;
+ } else if (strstr(class, "text")) {
+ which = CURS_TERM;
+ } else if (strstr(name, "onsole")) {
+ which = CURS_TERM;
+ } else if (strstr(class, "onsole")) {
+ which = CURS_TERM;
+ } else if (strstr(name, "cmdtool")) {
+ which = CURS_TERM;
+ } else if (strstr(class, "cmdtool")) {
+ which = CURS_TERM;
+ } else if (strstr(name, "shelltool")) {
+ which = CURS_TERM;
+ } else if (strstr(class, "shelltool")) {
+ which = CURS_TERM;
+ }
+ }
+ }
+ }
+ return which;
+}
+
+static void set_cursor_was_changed(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ if (! s) {
+ return;
+ }
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ cl->cursorWasChanged = TRUE;
+ }
+ rfbReleaseClientIterator(iter);
+}
+
+#if 0
+/* not yet used */
+static void set_cursor_was_moved(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+
+ if (! s) {
+ return;
+ }
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ cl->cursorWasMoved = TRUE;
+ }
+ rfbReleaseClientIterator(iter);
+}
+#endif
+
+void restore_cursor_shape_updates(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ int count = 0;
+
+ if (! s || ! s->clientHead) {
+ return;
+ }
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ int changed = 0;
+ ClientData *cd = (ClientData *) cl->clientData;
+
+ if (cd->had_cursor_shape_updates) {
+ rfbLog("restoring enableCursorShapeUpdates for client"
+ " 0x%x\n", cl);
+ cl->enableCursorShapeUpdates = TRUE;
+ changed = 1;
+ }
+ if (cd->had_cursor_pos_updates) {
+ rfbLog("restoring enableCursorPosUpdates for client"
+ " 0x%x\n", cl);
+ cl->enableCursorPosUpdates = TRUE;
+ changed = 1;
+ }
+ if (changed) {
+ cl->cursorWasChanged = TRUE;
+ count++;
+ }
+ }
+ rfbReleaseClientIterator(iter);
+}
+
+void disable_cursor_shape_updates(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ static int changed = 0;
+ int count = 0;
+
+ if (! s || ! s->clientHead) {
+ return;
+ }
+
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ ClientData *cd;
+ cd = (ClientData *) cl->clientData;
+
+ if (cl->enableCursorShapeUpdates) {
+ cd->had_cursor_shape_updates = 1;
+ count++;
+ if (debug_pointer) {
+ rfbLog("%s disable HCSU\n", cl->host);
+ }
+ }
+ if (cl->enableCursorPosUpdates) {
+ cd->had_cursor_pos_updates = 1;
+ count++;
+ if (debug_pointer) {
+ rfbLog("%s disable HCPU\n", cl->host);
+ }
+ }
+
+ cl->enableCursorShapeUpdates = FALSE;
+ cl->enableCursorPosUpdates = FALSE;
+ cl->cursorWasChanged = FALSE;
+ }
+ rfbReleaseClientIterator(iter);
+
+ if (count) {
+ changed = 1;
+ }
+}
+
+int cursor_shape_updates_clients(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ int count = 0;
+
+ if (! s) {
+ return 0;
+ }
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ if (cl->enableCursorShapeUpdates) {
+ count++;
+ }
+ }
+ rfbReleaseClientIterator(iter);
+ return count;
+}
+
+int cursor_pos_updates_clients(rfbScreenInfoPtr s) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ int count = 0;
+
+ if (! s) {
+ return 0;
+ }
+ iter = rfbGetClientIterator(s);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ if (cl->enableCursorPosUpdates) {
+ count++;
+ }
+ }
+ rfbReleaseClientIterator(iter);
+ return count;
+}
+
+/*
+ * Record rfb cursor position screen->cursorX, etc (a la defaultPtrAddEvent())
+ * Then set up for sending rfbCursorPosUpdates back
+ * to clients that understand them. This seems to be TightVNC specific.
+ */
+void cursor_position(int x, int y) {
+ rfbClientIteratorPtr iter;
+ rfbClientPtr cl;
+ int cnt = 0, nonCursorPosUpdates_clients = 0;
+ int x_in = x, y_in = y;
+
+ /* x and y are current positions of X11 pointer on the X11 display */
+ if (!screen) {
+ return;
+ }
+
+ if (scaling) {
+ x = ((double) x / dpy_x) * scaled_x;
+ x = nfix(x, scaled_x);
+ y = ((double) y / dpy_y) * scaled_y;
+ y = nfix(y, scaled_y);
+ }
+
+ if (x == screen->cursorX && y == screen->cursorY) {
+ return;
+ }
+
+ LOCK(screen->cursorMutex);
+ screen->cursorX = x;
+ screen->cursorY = y;
+ UNLOCK(screen->cursorMutex);
+
+ iter = rfbGetClientIterator(screen);
+ while( (cl = rfbClientIteratorNext(iter)) ) {
+ if (! cl->enableCursorPosUpdates) {
+ nonCursorPosUpdates_clients++;
+ continue;
+ }
+ if (! cursor_pos_updates) {
+ continue;
+ }
+ if (cl == last_pointer_client) {
+ /*
+ * special case if this client was the last one to
+ * send a pointer position.
+ */
+ if (x_in == cursor_x && y_in == cursor_y) {
+ cl->cursorWasMoved = FALSE;
+ } else {
+ /* an X11 app evidently warped the pointer */
+ if (debug_pointer) {
+ rfbLog("cursor_position: warp "
+ "detected dx=%3d dy=%3d\n",
+ cursor_x - x, cursor_y - y);
+ }
+ cl->cursorWasMoved = TRUE;
+ cnt++;
+ }
+ } else {
+ cl->cursorWasMoved = TRUE;
+ cnt++;
+ }
+ }
+ rfbReleaseClientIterator(iter);
+
+ if (debug_pointer && cnt) {
+ rfbLog("cursor_position: sent position x=%3d y=%3d to %d"
+ " clients\n", x, y, cnt);
+ }
+}
+
+static void set_rfb_cursor(int which) {
+
+ if (! show_cursor) {
+ return;
+ }
+ if (! screen) {
+ return;
+ }
+
+ if (!cursors[which] || !cursors[which]->rfb) {
+ rfbLog("non-existent cursor: which=%d\n", which);
+ return;
+ } else {
+ rfbSetCursor(screen, cursors[which]->rfb);
+ }
+}
+
+void set_no_cursor(void) {
+ set_rfb_cursor(CURS_EMPTY);
+}
+
+int set_cursor(int x, int y, int which) {
+ static int last = -1;
+ int changed_cursor = 0;
+
+ if (x || y) {} /* unused vars warning: */
+
+ if (which < 0) {
+ which = last;
+ }
+ if (last < 0 || which != last) {
+ set_rfb_cursor(which);
+ changed_cursor = 1;
+ }
+ last = which;
+
+ return changed_cursor;
+}
+
+/*
+ * routine called periodically to update cursor aspects, this catches
+ * warps and cursor shape changes.
+ */
+int check_x11_pointer(void) {
+ Window root_w, child_w;
+ rfbBool ret;
+ int root_x, root_y, win_x, win_y;
+ int x, y;
+ unsigned int mask;
+
+ if (raw_fb && ! dpy) return 0; /* raw_fb hack */
+
+ X_LOCK;
+ ret = XQueryPointer(dpy, rootwin, &root_w, &child_w, &root_x, &root_y,
+ &win_x, &win_y, &mask);
+ X_UNLOCK;
+
+ if (! ret) {
+ return 0;
+ }
+ if (debug_pointer) {
+ static int last_x = -1, last_y = -1;
+ if (root_x != last_x || root_y != last_y) {
+ rfbLog("XQueryPointer: x:%4d, y:%4d)\n",
+ root_x, root_y);
+ }
+ last_x = root_x;
+ last_y = root_y;
+ }
+
+ /* offset subtracted since XQueryPointer relative to rootwin */
+ x = root_x - off_x - coff_x;
+ y = root_y - off_y - coff_y;
+
+ /* record the cursor position in the rfb screen */
+ cursor_position(x, y);
+
+ /* change the cursor shape if necessary */
+ return set_cursor(x, y, get_which_cursor());
+}
+
+