|
|
|
/*
|
|
|
|
Copyright (C) 2002-2009 Karl J. Runge <runge@karlrunge.com>
|
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
This file is part of x11vnc.
|
|
|
|
|
|
|
|
x11vnc 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.
|
|
|
|
|
|
|
|
x11vnc 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 x11vnc; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
|
|
|
|
or see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
In addition, as a special exception, Karl J. Runge
|
|
|
|
gives permission to link the code of its release of x11vnc with the
|
|
|
|
OpenSSL project's "OpenSSL" library (or with modified versions of it
|
|
|
|
that use the same license as the "OpenSSL" library), and distribute
|
|
|
|
the linked executables. You must obey the GNU General Public License
|
|
|
|
in all respects for all of the code used other than "OpenSSL". If you
|
|
|
|
modify this file, you may extend this exception to your version of the
|
|
|
|
file, but you are not obligated to do so. If you do not wish to do
|
|
|
|
so, delete this exception statement from your version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* -- win_utils.c -- */
|
|
|
|
|
|
|
|
#include "x11vnc.h"
|
|
|
|
#include "xinerama.h"
|
|
|
|
#include "winattr_t.h"
|
|
|
|
#include "cleanup.h"
|
|
|
|
#include "xwrappers.h"
|
|
|
|
#include "connections.h"
|
|
|
|
#include "xrandr.h"
|
|
|
|
#include "macosx.h"
|
|
|
|
|
|
|
|
winattr_t *stack_list = NULL;
|
|
|
|
int stack_list_len = 0;
|
|
|
|
int stack_list_num = 0;
|
|
|
|
|
|
|
|
|
|
|
|
Window parent_window(Window win, char **name);
|
|
|
|
int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet);
|
|
|
|
Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
|
|
|
|
int *dst_y, Window *child, int bequiet);
|
|
|
|
int get_window_size(Window win, int *w, int *h);
|
|
|
|
void snapshot_stack_list(int free_only, double allowed_age);
|
|
|
|
int get_boff(void);
|
|
|
|
int get_bwin(void);
|
|
|
|
void update_stack_list(void);
|
|
|
|
Window query_pointer(Window start);
|
|
|
|
unsigned int mask_state(void);
|
|
|
|
int pick_windowid(unsigned long *num);
|
|
|
|
Window descend_pointer(int depth, Window start, char *name_info, int len);
|
|
|
|
void id_cmd(char *cmd);
|
|
|
|
|
|
|
|
|
|
|
|
Window parent_window(Window win, char **name) {
|
|
|
|
#if !NO_X11
|
|
|
|
Window r, parent;
|
|
|
|
Window *list;
|
|
|
|
XErrorHandler old_handler;
|
|
|
|
unsigned int nchild;
|
|
|
|
int rc;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (name != NULL) {
|
|
|
|
*name = NULL;
|
|
|
|
}
|
|
|
|
RAWFB_RET(None)
|
|
|
|
#if NO_X11
|
|
|
|
nox11_exit(1);
|
|
|
|
if (!name || !win) {}
|
|
|
|
return None;
|
|
|
|
#else
|
|
|
|
|
|
|
|
old_handler = XSetErrorHandler(trap_xerror);
|
|
|
|
trapped_xerror = 0;
|
|
|
|
rc = XQueryTree_wr(dpy, win, &r, &parent, &list, &nchild);
|
|
|
|
XSetErrorHandler(old_handler);
|
|
|
|
|
|
|
|
if (! rc || trapped_xerror) {
|
|
|
|
trapped_xerror = 0;
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
trapped_xerror = 0;
|
|
|
|
|
|
|
|
if (list) {
|
|
|
|
XFree_wr(list);
|
|
|
|
}
|
|
|
|
if (parent && name) {
|
|
|
|
XFetchName(dpy, parent, name);
|
|
|
|
}
|
|
|
|
return parent;
|
|
|
|
#endif /* NO_X11 */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* trapping utility to check for a valid window: */
|
|
|
|
int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet) {
|
|
|
|
XWindowAttributes attr, *pattr;
|
|
|
|
#if !NO_X11
|
|
|
|
XErrorHandler old_handler;
|
|
|
|
int ok = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (attr_ret == NULL) {
|
|
|
|
pattr = &attr;
|
|
|
|
} else {
|
|
|
|
pattr = attr_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (win == None) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef MACOSX
|
|
|
|
if (macosx_console) {
|
|
|
|
return macosx_valid_window(win, attr_ret);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
RAWFB_RET(0)
|
|
|
|
|
|
|
|
#if NO_X11
|
|
|
|
nox11_exit(1);
|
|
|
|
if (!win || !attr_ret || !bequiet) {}
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
|
|
|
|
old_handler = XSetErrorHandler(trap_xerror);
|
|
|
|
trapped_xerror = 0;
|
|
|
|
if (XGetWindowAttributes(dpy, win, pattr)) {
|
|
|
|
ok = 1;
|
|
|
|
}
|
|
|
|
if (trapped_xerror && trapped_xerror_event) {
|
|
|
|
if (! quiet && ! bequiet) {
|
|
|
|
rfbLog("valid_window: trapped XError: %s (0x%lx)\n",
|
|
|
|
xerror_string(trapped_xerror_event), win);
|
|
|
|
}
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
XSetErrorHandler(old_handler);
|
|
|
|
trapped_xerror = 0;
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
#endif /* NO_X11 */
|
|
|
|
}
|
|
|
|
|
|
|
|
Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
|
|
|
|
int *dst_y, Window *child, int bequiet) {
|
|
|
|
XErrorHandler old_handler = NULL;
|
|
|
|
Bool ok = False;
|
|
|
|
|
|
|
|
RAWFB_RET(False)
|
|
|
|
#if NO_X11
|
|
|
|
nox11_exit(1);
|
|
|
|
if (!src || !dst || !src_x || !src_y || !dst_x || !dst_y || !child || !bequiet) {}
|
|
|
|
if (!old_handler || !ok) {}
|
|
|
|
return False;
|
|
|
|
#else
|
|
|
|
|
|
|
|
trapped_xerror = 0;
|
|
|
|
old_handler = XSetErrorHandler(trap_xerror);
|
|
|
|
if (XTranslateCoordinates(dpy, src, dst, src_x, src_y, dst_x,
|
|
|
|
dst_y, child)) {
|
|
|
|
ok = True;
|
|
|
|
}
|
|
|
|
if (trapped_xerror && trapped_xerror_event) {
|
|
|
|
if (! quiet && ! bequiet) {
|
|
|
|
rfbLog("xtranslate: trapped XError: %s (0x%lx)\n",
|
|
|
|
xerror_string(trapped_xerror_event), src);
|
|
|
|
}
|
|
|
|
ok = False;
|
|
|
|
}
|
|
|
|
XSetErrorHandler(old_handler);
|
|
|
|
trapped_xerror = 0;
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
#endif /* NO_X11 */
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_window_size(Window win, int *w, int *h) {
|
|
|
|
XWindowAttributes attr;
|
|
|
|
/* valid_window? */
|
|
|
|
if (valid_window(win, &attr, 1)) {
|
|
|
|
*w = attr.width;
|
|
|
|
*h = attr.height;
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For use in the -wireframe stuff, save the stacking order of the direct
|
|
|
|
* children of the root window. Ideally done before we send ButtonPress
|
|
|
|
* to the X server.
|
|
|
|
*/
|
|
|
|
void snapshot_stack_list(int free_only, double allowed_age) {
|
|
|
|
static double last_snap = 0.0, last_free = 0.0;
|
|
|
|
double now;
|
|
|
|
int num, rc, i, j;
|
|
|
|
unsigned int ui;
|
|
|
|
Window r, w;
|
|
|
|
Window *list;
|
|
|
|
|
|
|
|
if (! stack_list) {
|
|
|
|
stack_list = (winattr_t *) malloc(256*sizeof(winattr_t));
|
|
|
|
stack_list_num = 0;
|
|
|
|
stack_list_len = 256;
|
|
|
|
}
|
|
|
|
|
|
|
|
dtime0(&now);
|
|
|
|
if (free_only) {
|
|
|
|
/* we really don't free it, just reset to zero windows */
|
|
|
|
stack_list_num = 0;
|
|
|
|
last_free = now;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stack_list_num && now < last_snap + allowed_age) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
stack_list_num = 0;
|
|
|
|
last_free = now;
|
|
|
|
|
|
|
|
#ifdef MACOSX
|
|
|
|
if (! macosx_console) {
|
|
|
|
RAWFB_RET_VOID
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
RAWFB_RET_VOID
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if NO_X11 && !defined(MACOSX)
|
|
|
|
num = rc = i = j = 0; /* compiler warnings */
|
|
|
|
ui = 0;
|
|
|
|
r = w = None;
|
|
|
|
list = NULL;
|
|
|
|
return;
|
|
|
|
#else
|
|
|
|
|
|
|
|
X_LOCK;
|
|
|
|
/* no need to trap error since rootwin */
|
|
|
|
rc = XQueryTree_wr(dpy, rootwin, &r, &w, &list, &ui);
|
|
|
|
num = (int) ui;
|
|
|
|
|
|
|
|
if (! rc) {
|
|
|
|
stack_list_num = 0;
|
|
|
|
last_free = now;
|
|
|
|
last_snap = 0.0;
|
|
|
|
X_UNLOCK;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_snap = now;
|
|
|
|
if (num > stack_list_len + blackouts) {
|
|
|
|
int n = 2*num;
|
|
|
|
free(stack_list);
|
|
|
|
stack_list = (winattr_t *) malloc(n*sizeof(winattr_t));
|
|
|
|
stack_list_len = n;
|
|
|
|
}
|
|
|
|
j = 0;
|
|
|
|
for (i=0; i<num; i++) {
|
|
|
|
stack_list[j].win = list[i];
|
|
|
|
stack_list[j].fetched = 0;
|
|
|
|
stack_list[j].valid = 0;
|
|
|
|
stack_list[j].time = now;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
for (i=0; i<blackouts; i++) {
|
|
|
|
stack_list[j].win = get_boff() + 1;
|
|
|
|
stack_list[j].fetched = 1;
|
|
|
|
stack_list[j].valid = 1;
|
|
|
|
stack_list[j].x = blackr[i].x1;
|
|
|
|
stack_list[j].y = blackr[i].y1;
|
|
|
|
stack_list[j].width = blackr[i].x2 - blackr[i].x1;
|
|
|
|
stack_list[j].height = blackr[i].y2 - blackr[i].y1;
|
|
|
|
stack_list[j].time = now;
|
|
|
|
stack_list[j].map_state = IsViewable;
|
|
|
|
stack_list[j].rx = -1;
|
|
|
|
stack_list[j].ry = -1;
|
|
|
|
j++;
|
|
|
|
|
|
|
|
if (0) fprintf(stderr, "blackr: %d %dx%d+%d+%d\n", i,
|
|
|
|
stack_list[j-1].width, stack_list[j-1].height,
|
|
|
|
stack_list[j-1].x, stack_list[j-1].y);
|
|
|
|
|
|
|
|
}
|
|
|
|
stack_list_num = num + blackouts;
|
|
|
|
if (debug_wireframe > 1) {
|
|
|
|
fprintf(stderr, "snapshot_stack_list: num=%d len=%d\n",
|
|
|
|
stack_list_num, stack_list_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
XFree_wr(list);
|
|
|
|
X_UNLOCK;
|
|
|
|
#endif /* NO_X11 */
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_boff(void) {
|
|
|
|
if (macosx_console) {
|
|
|
|
return 0x1000000;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_bwin(void) {
|
|
|
|
return 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
void update_stack_list(void) {
|
|
|
|
int k;
|
|
|
|
double now;
|
|
|
|
XWindowAttributes attr;
|
|
|
|
int boff, bwin;
|
|
|
|
|
|
|
|
if (! stack_list) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (! stack_list_num) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dtime0(&now);
|
|
|
|
|
|
|
|
boff = get_boff();
|
|
|
|
bwin = get_bwin();
|
|
|
|
|
|
|
|
X_LOCK;
|
|
|
|
for (k=0; k < stack_list_num; k++) {
|
|
|
|
Window win = stack_list[k].win;
|
|
|
|
if (win != None && boff <= (int) win && (int) win < boff + bwin) {
|
|
|
|
; /* special, blackout */
|
|
|
|
} else if (!valid_window(win, &attr, 1)) {
|
|
|
|
stack_list[k].valid = 0;
|
|
|
|
} else {
|
|
|
|
stack_list[k].valid = 1;
|
|
|
|
stack_list[k].x = attr.x;
|
|
|
|
stack_list[k].y = attr.y;
|
|
|
|
stack_list[k].width = attr.width;
|
|
|
|
stack_list[k].height = attr.height;
|
|
|
|
stack_list[k].border_width = attr.border_width;
|
|
|
|
stack_list[k].depth = attr.depth;
|
|
|
|
stack_list[k].class = attr.class;
|
|
|
|
stack_list[k].backing_store = attr.backing_store;
|
|
|
|
stack_list[k].map_state = attr.map_state;
|
|
|
|
|
|
|
|
/* root_x, root_y not used for stack_list usage: */
|
|
|
|
stack_list[k].rx = -1;
|
|
|
|
stack_list[k].ry = -1;
|
|
|
|
}
|
|
|
|
stack_list[k].fetched = 1;
|
|
|
|
stack_list[k].time = now;
|
|
|
|
}
|
|
|
|
X_UNLOCK;
|
|
|
|
if (0) fprintf(stderr, "update_stack_list[%d]: %.4f %.4f\n", stack_list_num, now - x11vnc_start, dtime(&now));
|
|
|
|
}
|
|
|
|
|
|
|
|
Window query_pointer(Window start) {
|
|
|
|
int rx, ry;
|
|
|
|
#if !NO_X11
|
|
|
|
Window r, c; /* compiler warnings */
|
|
|
|
int wx, wy;
|
|
|
|
unsigned int mask;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MACOSX
|
|
|
|
if (macosx_console) {
|
|
|
|
macosx_get_cursor_pos(&rx, &ry);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
RAWFB_RET(None)
|
|
|
|
|
|
|
|
#if NO_X11
|
|
|
|
if (!start) { rx = ry = 0; }
|
|
|
|
return None;
|
|
|
|
#else
|
|
|
|
if (start == None) {
|
|
|
|
start = rootwin;
|
|
|
|
}
|
|
|
|
if (XQueryPointer_wr(dpy, start, &r, &c, &rx, &ry, &wx, &wy, &mask)) {
|
|
|
|
return c;
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
#endif /* NO_X11 */
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int mask_state(void) {
|
|
|
|
#if NO_X11
|
|
|
|
RAWFB_RET(0)
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
Window r, c;
|
|
|
|
int rx, ry, wx, wy;
|
|
|
|
unsigned int mask;
|
|
|
|
|
|
|
|
RAWFB_RET(0)
|
|
|
|
|
|
|
|
if (XQueryPointer_wr(dpy, rootwin, &r, &c, &rx, &ry, &wx, &wy, &mask)) {
|
|
|
|
return mask;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* NO_X11 */
|
|
|
|
}
|
|
|
|
|
|
|
|
int pick_windowid(unsigned long *num) {
|
|
|
|
char line[512];
|
|
|
|
int ok = 0, n = 0, msec = 10, secmax = 15;
|
|
|
|
FILE *p;
|
|
|
|
|
|
|
|
RAWFB_RET(0)
|
|
|
|
|
|
|
|
if (use_dpy) {
|
|
|
|
set_env("DISPLAY", use_dpy);
|
|
|
|
}
|
|
|
|
/* id */
|
|
|
|
if (no_external_cmds || !cmd_ok("id")) {
|
|
|
|
rfbLogEnable(1);
|
|
|
|
rfbLog("cannot run external commands in -nocmds mode:\n");
|
|
|
|
rfbLog(" \"%s\"\n", "xwininfo");
|
|
|
|
rfbLog(" exiting.\n");
|
|
|
|
clean_up_exit(1);
|
|
|
|
}
|
|
|
|
close_exec_fds();
|
|
|
|
p = popen("xwininfo", "r");
|
|
|
|
|
|
|
|
if (! p) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
fprintf(stderr, " Please select the window for x11vnc to poll\n");
|
|
|
|
fprintf(stderr, " by clicking the mouse in that window.\n");
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
|
|
|
while (msec * n++ < 1000 * secmax) {
|
|
|
|
unsigned long tmp;
|
|
|
|
char *q;
|
|
|
|
fd_set set;
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
if (screen && screen->clientHead) {
|
|
|
|
/* they may be doing the pointer-pick thru vnc: */
|
|
|
|
int nfds;
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = msec * 1000;
|
|
|
|
FD_ZERO(&set);
|
|
|
|
FD_SET(fileno(p), &set);
|
|
|
|
|
|
|
|
nfds = select(fileno(p)+1, &set, NULL, NULL, &tv);
|
|
|
|
|
|
|
|
if (nfds == 0 || nfds < 0) {
|
|
|
|
/*
|
|
|
|
* select timedout or error.
|
|
|
|
* note this rfbPE takes about 30ms too:
|
|
|
|
*/
|
|
|
|
rfbPE(-1);
|
|
|
|
XFlush_wr(dpy);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fgets(line, 512, p) == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
q = strstr(line, " id: 0x");
|
|
|
|
if (q) {
|
|
|
|
q += 5;
|
|
|
|
if (sscanf(q, "0x%lx ", &tmp) == 1) {
|
|
|
|
ok = 1;
|
|
|
|
*num = tmp;
|
|
|
|
fprintf(stderr, " Picked: 0x%lx\n\n", tmp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pclose(p);
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window descend_pointer(int depth, Window start, char *name_info, int len) {
|
|
|
|
#if NO_X11
|
|
|
|
RAWFB_RET(None)
|
|
|
|
if (!depth || !start || !name_info || !len) {}
|
|
|
|
return None;
|
|
|
|
#else
|
|
|
|
Window r, c, clast = None;
|
|
|
|
int i, rx, ry, wx, wy;
|
|
|
|
int written = 0, filled = 0;
|
|
|
|
char *store = NULL;
|
|
|
|
unsigned int m;
|
|
|
|
static XClassHint *classhint = NULL;
|
|
|
|
static char *nm_cache = NULL;
|
|
|
|
static int nm_cache_len = 0;
|
|
|
|
static Window prev_start = None;
|
|
|
|
|
|
|
|
RAWFB_RET(None)
|
|
|
|
|
|
|
|
if (! classhint) {
|
|
|
|
classhint = XAllocClassHint();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! nm_cache) {
|
|
|
|
nm_cache = (char *) malloc(1024);
|
|
|
|
nm_cache_len = 1024;
|
|
|
|
nm_cache[0] = '\0';
|
|
|
|
}
|
|
|
|
if (name_info && nm_cache_len < len) {
|
|
|
|
if (nm_cache) {
|
|
|
|
free(nm_cache);
|
|
|
|
}
|
|
|
|
nm_cache_len = 2*len;
|
|
|
|
nm_cache = (char *) malloc(nm_cache_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name_info) {
|
|
|
|
if (start != None && start == prev_start) {
|
|
|
|
store = NULL;
|
|
|
|
strncpy(name_info, nm_cache, len);
|
|
|
|
} else {
|
|
|
|
store = name_info;
|
|
|
|
name_info[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (start != None) {
|
|
|
|
c = start;
|
|
|
|
if (name_info) {
|
|
|
|
prev_start = start;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
c = rootwin;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<depth; i++) {
|
|
|
|
clast = c;
|
|
|
|
if (store && ! filled) {
|
|
|
|
char *name;
|
|
|
|
if (XFetchName(dpy, clast, &name) && name != NULL) {
|
|
|
|
int l = strlen(name);
|
|
|
|
if (written + l+2 < len) {
|
|
|
|
strcat(store, "^^");
|
|
|
|
written += 2;
|
|
|
|
strcat(store, name);
|
|
|
|
written += l;
|
|
|
|
} else {
|
|
|
|
filled = 1;
|
|
|
|
}
|
|
|
|
XFree_wr(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (store && classhint && ! filled) {
|
|
|
|
classhint->res_name = NULL;
|
|
|
|
classhint->res_class = NULL;
|
|
|
|
if (XGetClassHint(dpy, clast, classhint)) {
|
|
|
|
int l = 0;
|
|
|
|
if (classhint->res_class) {
|
|
|
|
l += strlen(classhint->res_class);
|
|
|
|
}
|
|
|
|
if (classhint->res_name) {
|
|
|
|
l += strlen(classhint->res_name);
|
|
|
|
}
|
|
|
|
if (written + l+4 < len) {
|
|
|
|
strcat(store, "##");
|
|
|
|
if (classhint->res_class) {
|
|
|
|
strcat(store,
|
|
|
|
classhint->res_class);
|
|
|
|
}
|
|
|
|
strcat(store, "++");
|
|
|
|
if (classhint->res_name) {
|
|
|
|
strcat(store,
|
|
|
|
classhint->res_name);
|
|
|
|
}
|
|
|
|
written += l+4;
|
|
|
|
} else {
|
|
|
|
filled = 1;
|
|
|
|
}
|
|
|
|
if (classhint->res_class) {
|
|
|
|
XFree_wr(classhint->res_class);
|
|
|
|
}
|
|
|
|
if (classhint->res_name) {
|
|
|
|
XFree_wr(classhint->res_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! XQueryPointer_wr(dpy, c, &r, &c, &rx, &ry, &wx, &wy, &m)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (! c) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (start != None && name_info) {
|
|
|
|
strncpy(nm_cache, name_info, nm_cache_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return clast;
|
|
|
|
#endif /* NO_X11 */
|
|
|
|
}
|
|
|
|
|
|
|
|
void id_cmd(char *cmd) {
|
|
|
|
int rc, dx = 0, dy = 0, dw = 0, dh = 0;
|
|
|
|
int x0, y0, w0, h0;
|
|
|
|
int x, y, w, h, do_move = 0, do_resize = 0;
|
|
|
|
int disp_x = DisplayWidth(dpy, scr);
|
|
|
|
int disp_y = DisplayHeight(dpy, scr);
|
|
|
|
Window win = subwin;
|
|
|
|
XWindowAttributes attr;
|
|
|
|
XErrorHandler old_handler = NULL;
|
|
|
|
Window twin;
|
|
|
|
|
|
|
|
if (!cmd || !strcmp(cmd, "")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (strstr(cmd, "win=") == cmd) {
|
|
|
|
if (! scan_hexdec(cmd + strlen("win="), &win)) {
|
|
|
|
rfbLog("id_cmd: incorrect win= hex/dec number: %s\n", cmd);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
char *q = strchr(cmd, ':');
|
|
|
|
if (!q) {
|
|
|
|
rfbLog("id_cmd: incorrect win=...: hex/dec number: %s\n", cmd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rfbLog("id_cmd:%s set window id to 0x%lx\n", cmd, win);
|
|
|
|
cmd = q+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!win) {
|
|
|
|
rfbLog("id_cmd:%s not in sub-window mode or no win=0xNNNN.\n", cmd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#if !NO_X11
|
|
|
|
X_LOCK;
|
|
|
|
if (!valid_window(win, &attr, 1)) {
|
|
|
|
X_UNLOCK;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
w0 = w = attr.width;
|
|
|
|
h0 = h = attr.height;
|
|
|
|
old_handler = XSetErrorHandler(trap_xerror);
|
|
|
|
trapped_xerror = 0;
|
|
|
|
XTranslateCoordinates(dpy, win, rootwin, 0, 0, &x, &y, &twin);
|
|
|
|
x0 = x;
|
|
|
|
y0 = y;
|
|
|
|
if (strstr(cmd, "move:") == cmd) {
|
|
|
|
if (sscanf(cmd, "move:%d%d", &dx, &dy) == 2) {
|
|
|
|
x = x + dx;
|
|
|
|
y = y + dy;
|
|
|
|
do_move = 1;
|
|
|
|
}
|
|
|
|
} else if (strstr(cmd, "resize:") == cmd) {
|
|
|
|
if (sscanf(cmd, "resize:%d%d", &dw, &dh) == 2) {
|
|
|
|
w = w + dw;
|
|
|
|
h = h + dh;
|
|
|
|
do_move = 1;
|
|
|
|
do_resize = 1;
|
|
|
|
}
|
|
|
|
} else if (strstr(cmd, "geom:") == cmd) {
|
|
|
|
if (parse_geom(cmd+strlen("geom:"), &w, &h, &x, &y, disp_x, disp_y)) {
|
|
|
|
do_move = 1;
|
|
|
|
do_resize = 1;
|
|
|
|
if (w <= 0) {
|
|
|
|
w = w0;
|
|
|
|
}
|
|
|
|
if (h <= 0) {
|
|
|
|
h = h0;
|
|
|
|
}
|
|
|
|
if (scaling && getenv("X11VNC_APPSHARE_ACTIVE")) {
|
|
|
|
x /= scale_fac_x;
|
|
|
|
y /= scale_fac_y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!strcmp(cmd, "raise")) {
|
|
|
|
rc = XRaiseWindow(dpy, win);
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else if (!strcmp(cmd, "lower")) {
|
|
|
|
rc = XLowerWindow(dpy, win);
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else if (!strcmp(cmd, "map")) {
|
|
|
|
rc= XMapRaised(dpy, win);
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else if (!strcmp(cmd, "unmap")) {
|
|
|
|
rc= XUnmapWindow(dpy, win);
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else if (!strcmp(cmd, "iconify")) {
|
|
|
|
rc= XIconifyWindow(dpy, win, scr);
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else if (strstr(cmd, "wm_name:") == cmd) {
|
|
|
|
rc= XStoreName(dpy, win, cmd+strlen("wm_name:"));
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else if (strstr(cmd, "icon_name:") == cmd) {
|
|
|
|
rc= XSetIconName(dpy, win, cmd+strlen("icon_name:"));
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else if (!strcmp(cmd, "wm_delete")) {
|
|
|
|
XClientMessageEvent ev;
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
|
|
ev.type = ClientMessage;
|
|
|
|
ev.send_event = True;
|
|
|
|
ev.display = dpy;
|
|
|
|
ev.window = win;
|
|
|
|
ev.message_type = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
|
|
|
ev.format = 32;
|
|
|
|
ev.data.l[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
|
|
|
rc = XSendEvent(dpy, win, False, 0, (XEvent *) &ev);
|
|
|
|
rfbLog("id_cmd:%s rc=%d\n", cmd, rc);
|
|
|
|
} else {
|
|
|
|
rfbLog("id_cmd:%s unrecognized command.\n", cmd);
|
|
|
|
}
|
|
|
|
if (do_move || do_resize) {
|
|
|
|
if (w >= disp_x) {
|
|
|
|
w = disp_x - 4;
|
|
|
|
}
|
|
|
|
if (h >= disp_y) {
|
|
|
|
h = disp_y - 4;
|
|
|
|
}
|
|
|
|
if (w < 1) {
|
|
|
|
w = 1;
|
|
|
|
}
|
|
|
|
if (h < 1) {
|
|
|
|
h = 1;
|
|
|
|
}
|
|
|
|
if (x + w > disp_x) {
|
|
|
|
x = disp_x - w - 1;
|
|
|
|
}
|
|
|
|
if (y + h > disp_y) {
|
|
|
|
y = disp_y - h - 1;
|
|
|
|
}
|
|
|
|
if (x < 0) {
|
|
|
|
x = 1;
|
|
|
|
}
|
|
|
|
if (y < 0) {
|
|
|
|
y = 1;
|
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
rc += XMoveWindow(dpy, win, x, y);
|
|
|
|
off_x = x;
|
|
|
|
off_y = y;
|
|
|
|
|
|
|
|
rc += XResizeWindow(dpy, win, w, h);
|
|
|
|
|
|
|
|
rfbLog("id_cmd:%s rc=%d dx=%d dy=%d dw=%d dh=%d %dx%d+%d+%d -> %dx%d+%d+%d\n",
|
|
|
|
cmd, rc, dx, dy, dw, dh, w0, h0, x0, y0, w, h, x, h);
|
|
|
|
}
|
|
|
|
XSync(dpy, False);
|
|
|
|
XSetErrorHandler(old_handler);
|
|
|
|
if (trapped_xerror) {
|
|
|
|
rfbLog("id_cmd:%s trapped_xerror.\n", cmd);
|
|
|
|
}
|
|
|
|
trapped_xerror = 0;
|
|
|
|
if (do_resize) {
|
|
|
|
rfbLog("id_cmd:%s calling check_xrandr_event.\n", cmd);
|
|
|
|
check_xrandr_event("id_cmd");
|
|
|
|
}
|
|
|
|
X_UNLOCK;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|