Commit 27a884d2 authored by runge's avatar runge

x11vnc: Mac OS X fb fixes and cuttext, -nodpms option, local user wireframing

parent 05ba45f7
2006-11-21 Karl Runge <runge@karlrunge.com>
* configure.ac: add DPMS detection.
2006-11-13 Karl Runge <runge@karlrunge.com>
* configure.ac: x11vnc warnings for no XTEST or SSL.
* prepare_x11vnc_dist.sh: to 0.8.4
......
......@@ -61,6 +61,7 @@ AH_TEMPLATE(HAVE_RECORD, [RECORD extension build environment present])
AH_TEMPLATE(HAVE_SOLARIS_XREADSCREEN, [Solaris XReadScreen available])
AH_TEMPLATE(HAVE_IRIX_XREADDISPLAY, [IRIX XReadDisplay available])
AH_TEMPLATE(HAVE_FBPM, [FBPM extension build environment present])
AH_TEMPLATE(HAVE_DPMS, [DPMS extension build environment present])
AH_TEMPLATE(HAVE_LINUX_VIDEODEV_H, [video4linux build environment present])
AH_TEMPLATE(HAVE_LINUX_FB_H, [linux fb device build environment present])
AH_TEMPLATE(HAVE_LINUX_INPUT_H, [linux/input.h present])
......@@ -119,6 +120,10 @@ elif test "$X_CFLAGS" != "-DX_DISPLAY_MISSING"; then
[#include <X11/Xlib.h>
#include <X11/Xmd.h>])
AC_CHECK_HEADER(X11/extensions/dpms.h,
[AC_DEFINE(HAVE_DPMS)], ,
[#include <X11/Xlib.h>])
AC_CHECK_LIB(Xtst, XTestGrabControl,
X_PRELIBS="-lXtst $X_PRELIBS"
[AC_DEFINE(HAVE_XTESTGRABCONTROL) HAVE_XTESTGRABCONTROL="true"], ,
......
2006-11-21 Karl Runge <runge@karlrunge.com>
* x11vnc: macosx: problem with padded framebuffer rows, wait for
user to switch back, CutText xfer support, ignore a few more
types of toplevels. Add local user wireframing. -dpms/-nodpms
option to work around kdesktop_lock problem.
2006-11-13 Karl Runge <runge@karlrunge.com>
* x11vnc: Native Mac OS X support.
......
This diff is collapsed.
......@@ -133,7 +133,7 @@ void clean_up_exit (int ret) {
unlink(client_connect_file);
}
}
if (! dpy) {
if (macosx_console) {
macosxCG_fini();
}
#endif
......
......@@ -748,7 +748,7 @@ void client_gone(rfbClientPtr client) {
clean_up_exit(0);
}
#ifdef MACOSX
if (! dpy && client_count == 0) {
if (macosx_console && client_count == 0) {
macosxCG_refresh_callback_off();
}
#endif
......@@ -2108,7 +2108,7 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
autorepeat(0, 0);
}
#ifdef MACOSX
if (! dpy && client_count == 1) {
if (macosx_console && client_count == 1) {
macosxCG_refresh_callback_on();
}
#endif
......
......@@ -1246,7 +1246,7 @@ static int get_exact_cursor(int init) {
}
#ifdef MACOSX
if (! dpy) {
if (macosx_console) {
return macosx_get_cursor();
}
#endif
......@@ -1325,6 +1325,11 @@ fprintf(stderr, "sc: %d %d/%d %d - %d %d\n", serial, w, h, cbpp, xhot, yhot);
* got a hit with an existing cursor,
* use that one.
*/
#ifdef MACOSX
if (now > curs_times[i] + 1) {
continue;
}
#endif
last_cursor = curs_index[i];
curs_times[i] = now;
last_index = i;
......@@ -1481,11 +1486,7 @@ int get_which_cursor(void) {
}
if (mode == 3) {
int try_macosx = 0;
#ifdef MACOSX
if (! dpy) try_macosx = 1;
#endif
if ((xfixes_present && use_xfixes) || try_macosx) {
if ((xfixes_present && use_xfixes) || macosx_console) {
if (db) fprintf(stderr, "get_which_cursor call get_exact_cursor\n");
return get_exact_cursor(0);
}
......@@ -1846,24 +1847,23 @@ int check_x11_pointer(void) {
int root_x, root_y, win_x, win_y;
int x, y;
unsigned int mask;
int macosx_rawfb_ret = 0;
if (unixpw_in_progress) return 0;
#ifdef MACOSX
if (macosx_rawfb_ret) {
RAWFB_RET(0)
}
if (dpy) {
;
} else {
if (macosx_console) {
ret = macosx_get_cursor_pos(&root_x, &root_y);
} else {
RAWFB_RET(0)
}
#else
RAWFB_RET(0)
#if NO_X11
# if NO_X11
return 0;
#endif
# endif
#endif
......@@ -1876,6 +1876,7 @@ int check_x11_pointer(void) {
}
#endif /* NO_X11 */
if (0) fprintf(stderr, "check_x11_pointer %d %d\n", root_x, root_y);
if (! ret) {
return 0;
}
......
This diff is collapsed.
......@@ -2870,7 +2870,7 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
last_rfb_key_accepted = TRUE;
if (pipeinput_fh != NULL || pipeinput_int) {
pipe_keyboard(down, keysym, client);
pipe_keyboard(down, keysym, client); /* MACOSX here. */
if (! pipeinput_tee) {
if (! view_only || raw_fb) { /* raw_fb hack */
last_keyboard_client = client;
......
......@@ -29,6 +29,8 @@ void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client);
char *macosx_get_fb_addr(void);
int macosx_get_cursor(void);
int macosx_get_cursor_pos(int *, int *);
void macosx_send_sel(char *, int);
void macosx_set_sel(char *, int);
int macosx_valid_window(Window, XWindowAttributes*);
Status macosx_xquerytree(Window w, Window *root_return, Window *parent_return,
......@@ -57,6 +59,12 @@ int macosx_get_cursor(void) {
int macosx_get_cursor_pos(int *x, int *y) {
return 0;
}
void macosx_send_sel(char * str, int len) {
return;
}
void macosx_set_sel(char * str, int len) {
return;
}
int macosx_valid_window(Window w, XWindowAttributes* a) {
return 0;
}
......@@ -163,6 +171,7 @@ char *macosx_console_guess(char *str, int *fd) {
void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client) {
allowed_input_t input;
static int last_mask = 0;
int rc;
if (0) fprintf(stderr, "macosx_pointer_command: %d %d - %d\n", x, y, mask);
......@@ -191,9 +200,18 @@ void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client) {
macosxCG_pointer_inject(mask, x, y);
if (cursor_x != x || cursor_y != y) {
last_pointer_motion_time = dnow();
}
cursor_x = x;
cursor_y = y;
if (last_mask != mask) {
last_pointer_click_time = dnow();
}
last_mask = mask;
/* record the x, y position for the rfb screen as well. */
cursor_position(x, y);
......@@ -226,11 +244,57 @@ void macosx_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
}
extern void macosxGCS_poll_pb(void);
int macosx_get_cursor_pos(int *x, int *y) {
macosxCG_get_cursor_pos(x, y);
if (nofb) {
/* good time to poll the pasteboard */
macosxGCS_poll_pb();
}
return 1;
}
static char *cuttext = NULL;
static int cutlen = 0;
void macosx_send_sel(char *str, int len) {
if (screen && all_clients_initialized()) {
if (cuttext) {
int n = cutlen;
if (len < n) {
n = len;
}
if (!memcmp(str, cuttext, (size_t) n)) {
/* the same text we set pasteboard to ... */
return;
}
}
if (debug_sel) {
rfbLog("macosx_send_sel: %d\n", len);
}
rfbSendServerCutText(screen, str, len);
}
}
void macosx_set_sel(char *str, int len) {
if (screen && all_clients_initialized()) {
if (cutlen <= len) {
if (cuttext) {
free(cuttext);
}
cutlen = 2*(len+1);
cuttext = (char *) calloc(cutlen, 1);
}
memcpy(cuttext, str, (size_t) len);
cuttext[len] = '\0';
if (debug_sel) {
rfbLog("macosx_set_sel: %d\n", len);
}
macosxGCS_set_pasteboard(str, len);
}
}
int macosx_get_cursor(void) {
return macosxCG_get_cursor();
}
......@@ -346,23 +410,13 @@ Status macosx_xquerytree(Window w, Window *root_return, Window *parent_return,
*root_return = (Window) 0;
*parent_return = (Window) 0;
#if 0
fprintf(stderr, "macosx_xquerytree in.\n");
#endif
macosxCGS_get_all_windows();
#if 0
fprintf(stderr, "macosx_xquerytree got windows.\n");
#endif
n = 0;
for (k = 0; k < CGS_levelmax; k++) {
for (k = CGS_levelmax - 1; k >= 0; k--) {
for (i = macwinmax - 1; i >= 0; i--) {
if (macwins[i].level == CGS_levels[k]) {
#if 0
fprintf(stderr, "k=%d i=%d n=%d\n", k, i, n);
#endif
if (0) fprintf(stderr, "k=%d i=%d n=%d\n", k, i, n);
cret[n++] = (Window) macwins[i].win;
}
}
......
......@@ -13,6 +13,8 @@ extern int macosx_get_cursor_pos(int *, int *);
extern int macosx_valid_window(Window, XWindowAttributes*);
extern Status macosx_xquerytree(Window w, Window *root_return, Window *parent_return,
Window **children_return, unsigned int *nchildren_return);
extern void macosx_send_sel(char *, int);
extern void macosx_set_sel(char *, int);
......
......@@ -44,6 +44,7 @@ static void macosxCG_callback(CGRectCount n, const CGRect *rects, void *dum) {
}
int dragum(void) {
#if 0
int x =200, y = 150, dy = 10, i;
CGPoint loc;
......@@ -58,6 +59,7 @@ int dragum(void) {
}
CGPostMouseEvent(loc, TRUE, 1, FALSE);
usleep(4*1000*1000);
#endif
return 0;
}
......@@ -85,6 +87,7 @@ void macosxCG_refresh_callback_off(void) {
}
extern int macosx_noscreensaver;
extern void macosxGCS_initpb(void);
void macosxCG_init(void) {
if (displayID == NULL) {
......@@ -106,6 +109,7 @@ void macosxCG_init(void) {
if (macosx_noscreensaver) {
macosxCGP_screensaver_timer_on();
}
macosxGCS_initpb();
}
}
......@@ -117,22 +121,63 @@ void macosxCG_fini(void) {
macosxCG_refresh_callback_off();
}
extern int dpy_x, dpy_y;
extern int client_count;
extern int dpy_x, dpy_y, bpp, wdpy_x, wdpy_y;
extern int client_count, nofb;
extern void do_new_fb(int);
extern int macosx_wait_for_switch, macosx_resize;
void macosxCG_event_loop(void) {
OSStatus rc;
int nbpp;
macosxGCS_poll_pb();
if (nofb) {
return;
}
rc = RunCurrentEventLoop(kEventDurationSecond/30);
if (client_count) {
macosxCG_refresh_callback_on();
} else {
macosxCG_refresh_callback_off();
}
if (dpy_x != (int) CGDisplayPixelsWide(displayID)) {
if (dpy_y != (int) CGDisplayPixelsHigh(displayID)) {
nbpp = macosxCG_CGDisplayBitsPerPixel();
if (nbpp > 0 && nbpp != bpp) {
if (macosx_resize) {
do_new_fb(1);
}
} else if (wdpy_x != (int) CGDisplayPixelsWide(displayID)) {
if (wdpy_y != (int) CGDisplayPixelsHigh(displayID)) {
if (macosx_wait_for_switch) {
int cnt = 0;
while (1) {
if(CGDisplayPixelsWide(displayID) > 0) {
if(CGDisplayPixelsHigh(displayID) > 0) {
usleep(500*1000);
break;
}
}
if ((cnt++ % 120) == 0) {
fprintf(stderr, "waiting for user to "
"switch back..\n");
}
sleep(1);
}
if (wdpy_x == (int) CGDisplayPixelsWide(displayID)) {
if (wdpy_y == (int) CGDisplayPixelsHigh(displayID)) {
fprintf(stderr, "we're back...\n");
return;
}
}
}
if (macosx_resize) {
do_new_fb(1);
}
}
}
}
......@@ -171,6 +216,16 @@ extern CGError CGSGetCurrentCursorLocation(CGSConnectionRef, CGPoint*);
extern int CGSCurrentCursorSeed(void);
extern int CGSHardwareCursorActive();
static unsigned int last_local_button_mask = 0;
static unsigned int last_local_mod_mask = 0;
static int last_local_x = 0;
static int last_local_y = 0;
extern unsigned int display_button_mask;
extern unsigned int display_mod_mask;
extern int got_local_pointer_input;
extern time_t last_local_input;
static CGPoint current_cursor_pos(void) {
CGPoint pos;
pos.x = 0;
......@@ -183,6 +238,25 @@ static CGPoint current_cursor_pos(void) {
if (CGSGetCurrentCursorLocation(conn, &pos) != kCGErrorSuccess) {
fprintf(stderr, "CGSGetCurrentCursorLocation error\n");
}
display_button_mask = GetCurrentButtonState();
#if 0
/* not used yet */
display_mod_mask = GetCurrentKeyModifiers();
#endif
if (last_local_button_mask != display_button_mask) {
got_local_pointer_input++;
last_local_input = time(NULL);
} else if (pos.x != last_local_x || pos.y != last_local_y) {
got_local_pointer_input++;
last_local_input = time(NULL);
}
last_local_button_mask = display_button_mask;
last_local_mod_mask = display_mod_mask;
last_local_x = pos.x;
last_local_y = pos.y;
return pos;
}
......@@ -199,29 +273,36 @@ extern int store_cursor(int serial, unsigned long *data, int w, int h, int cbpp,
int macosxCG_get_cursor(void) {
int last_idx = (int) get_cursor_serial(1);
int which = 1;
static CGPoint pos, lastpos;
static foo = 0;
CGError err;
int datasize, masksize, row_bytes, cdepth, comps, bpcomp;
CGRect rect;
CGPoint hot;
unsigned char *data;
int res, cursor_seed;
static int last_cursor_seed = -1;
static time_t last_fetch = 0;
time_t now = time(NULL);
if (last_idx) {
which = last_idx;
}
pos = current_cursor_pos();
if (cursor_seed == CGSCurrentCursorSeed()) {
return which;
}
if (! conn) {
if (CGSNewConnection(NULL, &conn) != kCGErrorSuccess) {
fprintf(stderr, "CGSNewConnection error\n");
return which;
}
}
cursor_seed = CGSCurrentCursorSeed();
if (last_idx && cursor_seed == last_cursor_seed) {
if (now < last_fetch + 2) {
return which;
}
}
last_cursor_seed = cursor_seed;
last_fetch = now;
if (CGSGetGlobalCursorDataSize(conn, &datasize) != kCGErrorSuccess) {
fprintf(stderr, "CGSGetGlobalCursorDataSize error\n");
return which;
......@@ -239,7 +320,6 @@ int macosxCG_get_cursor(void) {
if (cdepth == 24) {
cdepth = 32;
}
cursor_seed = CGSCurrentCursorSeed();
which = store_cursor(cursor_seed, (unsigned long*) data,
(int) rect.size.width, (int) rect.size.height, cdepth, (int) hot.x, (int) hot.y);
......@@ -248,21 +328,25 @@ int macosxCG_get_cursor(void) {
return(which);
}
extern int macosx_mouse_wheel_speed;
extern int macosx_swap23;
extern int off_x, coff_x, off_y, coff_y;
void macosxCG_pointer_inject(int mask, int x, int y) {
int swap23 = 1, rc;
int swap23 = macosx_swap23, rc;
int s1 = 0, s2 = 1, s3 = 2, s4 = 3, s5 = 4;
CGPoint loc;
int wheel_distance = 10;
int wheel_distance = macosx_mouse_wheel_speed;
static int cnt = 0;
loc.x = x;
loc.y = y;
if (swap23) {
s2 = 2;
s3 = 1;
}
loc.x = x + off_x + coff_x;
loc.y = y + off_y + coff_y;
if ((cnt++ % 10) == 0) {
macosxCGP_undim();
}
......
......@@ -15,6 +15,7 @@
extern CGDirectDisplayID displayID;
void macosxCGS_get_all_windows(void);
void macosxGCS_set_pasteboard(char *str, int len);
typedef CGError CGSError;
typedef long CGSWindowCount;
......@@ -79,12 +80,13 @@ void macosxCGS_get_all_windows(void) {
if (first) {
first = 0;
CGS_levelmax = 0;
CGS_levels[CGS_levelmax++] = (int) kCGDraggingWindowLevel; /* 500 */
if (0) CGS_levels[CGS_levelmax++] = (int) kCGHelpWindowLevel; /* 102 */
if (0) CGS_levels[CGS_levelmax++] = (int) kCGPopUpMenuWindowLevel; /* 101 */
CGS_levels[CGS_levelmax++] = (int) kCGMainMenuWindowLevelKey; /* 24 */
CGS_levels[CGS_levelmax++] = (int) kCGFloatingWindowLevel; /* 3 */
CGS_levels[CGS_levelmax++] = (int) kCGNormalWindowLevel; /* 0 */
CGS_levels[CGS_levelmax++] = (int) kCGDraggingWindowLevel; /* 500 ? */
if (0) CGS_levels[CGS_levelmax++] = (int) kCGHelpWindowLevel; /* 102 ? */
if (0) CGS_levels[CGS_levelmax++] = (int) kCGPopUpMenuWindowLevel; /* 101 pulldown menu */
CGS_levels[CGS_levelmax++] = (int) kCGMainMenuWindowLevelKey; /* 24 ? */
CGS_levels[CGS_levelmax++] = (int) kCGModalPanelWindowLevel; /* 8 open dialog box */
CGS_levels[CGS_levelmax++] = (int) kCGFloatingWindowLevel; /* 3 ? */
CGS_levels[CGS_levelmax++] = (int) kCGNormalWindowLevel; /* 0 regular window */
}
if (cid == NULL) {
......@@ -152,5 +154,79 @@ if (db) fprintf(stderr, "i=%03d ID: %06d x: %03d y: %03d w: %03d h: %03d leve
}
}
#if 1
NSLock *pblock = nil;
NSString *pbstr = nil;
NSString *cuttext = nil;
int pbcnt = -1;
NSStringEncoding pbenc = NSWindowsCP1252StringEncoding;
void macosxGCS_initpb(void) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
pblock = [[NSLock alloc] init];
if (![NSPasteboard generalPasteboard]) {
fprintf(stderr, "macosxGCS_initpb: pasteboard inaccessible.\n");
pbcnt = 0;
pbstr = [[NSString alloc] initWithString:@"\e<PASTEBOARD INACCESSIBLE>\e"];
}
[pool release];
}
void macosxGCS_set_pasteboard(char *str, int len) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if (pbcnt != 0) {
[pblock lock];
[cuttext release];
cuttext = [[NSString alloc] initWithData:[NSData dataWithBytes:str length:len] encoding: pbenc];
if ([[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]) {
NS_DURING
[[NSPasteboard generalPasteboard] setString:cuttext forType:NSStringPboardType];
NS_HANDLER
fprintf(stderr, "macosxGCS_set_pasteboard: problem writing to pasteboard\n");
NS_ENDHANDLER
} else {
fprintf(stderr, "macosxGCS_set_pasteboard: problem writing to pasteboard\n");
}
[cuttext release];
cuttext = nil;
[pblock unlock];
}
[pool release];
}
extern void macosx_send_sel(char *, int);
void macosxGCS_poll_pb(void) {
static double dlast = 0.0;
double now = dnow();
if (now < dlast + 0.2) {
return;
}
dlast = now;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pblock lock];
if (pbcnt != [[NSPasteboard generalPasteboard] changeCount]) {
pbcnt = [[NSPasteboard generalPasteboard] changeCount];
[pbstr release];
pbstr = nil;
if ([[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]) {
pbstr = [[[NSPasteboard generalPasteboard] stringForType:NSStringPboardType] copy];
if (pbstr) {
NSData *str = [pbstr dataUsingEncoding:pbenc allowLossyConversion:YES];
if ([str length]) {
macosx_send_sel((char *) [str bytes], [str length]);
}
}
}
}
[pblock unlock];
[pool release];
}
#endif
#endif /* __APPLE__ */
......@@ -4,6 +4,7 @@
/* -- macosxCGS.h -- */
extern void macosxCGS_get_all_windows(void);
extern void macosxGCS_set_pasteboard(char *str, int len);
#endif /* _X11VNC_MACOSXCGS_H */
......@@ -129,9 +129,14 @@ int pipeinput_int = 0;
int pipeinput_cons_fd = -1;
char *pipeinput_cons_dev = NULL;
int macosx_nodimming = 0;
int macosx_nodimming = 0; /* Some native MacOSX server settings. */
int macosx_nosleep = 0;
int macosx_noscreensaver = 0;
int macosx_wait_for_switch = 1;
int macosx_mouse_wheel_speed = 5;
int macosx_console = 0;
int macosx_swap23 = 1;
int macosx_resize = 1;
unsigned long subwin = 0x0; /* -id, -sid */
int subwin_wait_mapped = 0;
......@@ -186,6 +191,7 @@ char *wireframe_copyrect_default = "always";
char *wireframe_copyrect_default = "never";
#endif
int wireframe_in_progress = 0;
int wireframe_local = 1;
/* T+B+L+R,tkey+presist_key,tmouse+persist_mouse */
char *scroll_copyrect_str = NULL;
......@@ -311,6 +317,8 @@ int watch_fbpm = 1; /* -nofbpm */
int watch_fbpm = 0;
#endif
int watch_dpms = 0; /* -dpms */
int watch_selection = 1; /* normal selection/cutbuffer maintenance */
int watch_primary = 1; /* more dicey, poll for changes in PRIMARY */
int watch_clipboard = 1;
......
......@@ -107,6 +107,11 @@ extern char *pipeinput_cons_dev;
extern int macosx_nodimming;
extern int macosx_nosleep;
extern int macosx_noscreensaver;
extern int macosx_wait_for_switch;
extern int macosx_mouse_wheel_speed;
extern int macosx_console;
extern int macosx_swap23;
extern int macosx_resize;
extern unsigned long subwin;
extern int subwin_wait_mapped;
......@@ -143,6 +148,7 @@ extern int cursor_shape_updates;
extern int use_xwarppointer;
extern int show_dragging;
extern int wireframe;
extern int wireframe_local;
extern char *wireframe_str;
extern char *wireframe_copyrect;
......@@ -231,6 +237,7 @@ extern int ui_skip;
extern int all_input;
extern int watch_fbpm;
extern int watch_dpms;
extern int watch_selection;
extern int watch_primary;
......
......@@ -4,14 +4,20 @@
void check_pm(void);
static void check_fbpm(void);
static void check_dpms(void);
#if LIBVNCSERVER_HAVE_FBPM
#include <X11/Xmd.h>
#include <X11/extensions/fbpm.h>
#endif
#if LIBVNCSERVER_HAVE_DPMS
#include <X11/extensions/dpms.h>
#endif
void check_pm(void) {
check_fbpm();
check_dpms();
/* someday dpms activities? */
}
......@@ -20,7 +26,7 @@ static void check_fbpm(void) {
#if LIBVNCSERVER_HAVE_FBPM
static int fbpm_capable = 0;
static time_t last_fbpm = 0;
int db = 1;
int db = 0;
CARD16 level;
BOOL enabled;
......@@ -28,12 +34,15 @@ static void check_fbpm(void) {
RAWFB_RET_VOID
if (! init_fbpm) {
if (getenv("FBPM_DEBUG")) {
db = atoi(getenv("FBPM_DEBUG"));
}
if (FBPMCapable(dpy)) {
fbpm_capable = 1;
rfbLog("X display is capable of FBPM.\n");
if (watch_fbpm) {
rfbLog("Preventing low-power FBPM modes when"
" VNC clients are connected.\n");
" clients are connected.\n");
}
} else {
if (! raw_fb_str) {
......@@ -95,3 +104,86 @@ static void check_fbpm(void) {
#endif
}
static void check_dpms(void) {
static int init_dpms = 0;
#if LIBVNCSERVER_HAVE_DPMS
static int dpms_capable = 0;
static time_t last_dpms = 0;
int db = 0;
CARD16 level;
BOOL enabled;
RAWFB_RET_VOID
if (! init_dpms) {
if (getenv("DPMS_DEBUG")) {
db = atoi(getenv("DPMS_DEBUG"));
}
if (DPMSCapable(dpy)) {
dpms_capable = 1;
rfbLog("X display is capable of DPMS.\n");
if (watch_dpms) {
rfbLog("Preventing low-power DPMS modes when"
" clients are connected.\n");
}
} else {
if (! raw_fb_str) {
rfbLog("X display is not capable of DPMS.\n");
}
dpms_capable = 0;
}
init_dpms = 1;
}
if (! watch_dpms) {
return;
}
if (! dpms_capable) {
return;
}
if (! client_count) {
return;
}
if (time(NULL) < last_dpms + 5) {
return;
}
last_dpms = time(NULL);
if (DPMSInfo(dpy, &level, &enabled)) {
if (db) fprintf(stderr, "DPMSInfo level: %d enabled: %d\n", level, enabled);
if (enabled && level != DPMSModeOn) {
char *from = "unknown-dpms-state";
XErrorHandler old_handler = XSetErrorHandler(trap_xerror);
trapped_xerror = 0;
if (level == DPMSModeStandby) {
from = "DPMSModeStandby";
} else if (level == DPMSModeSuspend) {
from = "DPMSModeSuspend";
} else if (level == DPMSModeOff) {
from = "DPMSModeOff";
}
rfbLog("switching DPMS state from %s to DPMSModeOn\n", from);
DPMSForceLevel(dpy, DPMSModeOn);
XSetErrorHandler(old_handler);
trapped_xerror = 0;
}
} else {
if (db) fprintf(stderr, "DPMSInfo failed.\n");
}
#else
RAWFB_RET_VOID
if (! init_dpms) {
if (! raw_fb_str) {
rfbLog("X DPMS extension not supported.\n");
}
init_dpms = 1;
}
#endif
}
......@@ -664,7 +664,7 @@ void pointer(int mask, int x, int y, rfbClientPtr client) {
}
if ((pipeinput_fh != NULL || pipeinput_int) && mask >= 0) {
pipe_pointer(mask, x, y, client);
pipe_pointer(mask, x, y, client); /* MACOSX here. */
if (! pipeinput_tee) {
if (! view_only || raw_fb) { /* raw_fb hack */
got_user_input++;
......
......@@ -2774,6 +2774,21 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("remote_cmd: enabling -nowireframe mode.\n");
wireframe = 0;
} else if (!strcmp(p, "wireframelocal") || !strcmp(p, "wfl")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, wireframe_local);
goto qry;
}
rfbLog("remote_cmd: enabling -wireframelocal mode.\n");
wireframe_local = 1;
} else if (!strcmp(p, "nowireframelocal") || !strcmp(p, "nowfl")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, !wireframe_local);
goto qry;
}
rfbLog("remote_cmd: enabling -nowireframelocal mode.\n");
wireframe_local = 0;
} else if (strstr(p, "wirecopyrect") == p) {
COLON_CHECK("wirecopyrect:")
if (query) {
......@@ -3385,6 +3400,21 @@ char *process_remote_cmd(char *cmd, int stringonly) {
rfbLog("remote_cmd: turning on -nofbpm mode.\n");
watch_fbpm = 1;
} else if (!strcmp(p, "dpms")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, !watch_dpms);
goto qry;
}
rfbLog("remote_cmd: turning off -nodpms mode.\n");
watch_dpms = 0;
} else if (!strcmp(p, "nodpms")) {
if (query) {
snprintf(buf, bufn, "ans=%s:%d", p, watch_dpms);
goto qry;
}
rfbLog("remote_cmd: turning on -nodpms mode.\n");
watch_dpms = 1;
} else if (strstr(p, "fs") == p) {
COLON_CHECK("fs:")
if (query) {
......
......@@ -2356,15 +2356,17 @@ int copy_screen(void) {
if (! fs_factor) {
return 0;
}
if (debug_tiles) fprintf(stderr, "copy_screen\n");
if (unixpw_in_progress) return 0;
block_size = (dpy_x * (dpy_y/fs_factor) * pixelsize);
if (! main_fb) {
return 0;
}
block_size = ((dpy_y/fs_factor) * main_bytes_per_line);
fbp = main_fb;
y = 0;
......@@ -2404,7 +2406,7 @@ static void snap_all_rawfb(void) {
if (xform24to32 && bpp == 32) {
pixelsize = 3;
}
sz = dpy_x * dpy_y * pixelsize;
sz = dpy_y * snap->bytes_per_line;
if (wdpy_x > dpy_x || wdpy_y > dpy_y) {
sz = wdpy_x * wdpy_y * pixelsize;
......@@ -2452,7 +2454,7 @@ static void snap_all_rawfb(void) {
for (h = 0; h < dpy_y; h++) {
memcpy(dst, src, dpy_x * pixelsize);
src += wdpy_x * pixelsize;
dst += dpy_x * pixelsize;
dst += snap->bytes_per_line;
}
}
}
......@@ -2481,6 +2483,9 @@ int copy_snap(void) {
if (rawfb_reset) {
initialize_raw_fb(1);
}
if (raw_fb_bytes_per_line != snap->bytes_per_line) {
read_all_at_once = 0;
}
if (read_all_at_once) {
snap_all_rawfb();
} else {
......@@ -2496,11 +2501,12 @@ if (db && snapcnt++ < 5) rfbLog("rawfb copy_snap took: %.5f secs\n", dnow() - st
return 0;
}
block_size = (dpy_x * (dpy_y/fs_factor) * pixelsize);
if (! snap_fb || ! snap || ! snaprect) {
return 0;
}
block_size = ((dpy_y/fs_factor) * snap->bytes_per_line);
fbp = snap_fb;
y = 0;
......@@ -2578,6 +2584,7 @@ static void nap_set(int tile_cnt) {
*/
void nap_sleep(int ms, int split) {
int i, input = got_user_input;
int gd = got_local_pointer_input;
for (i=0; i<split; i++) {
usleep(ms * 1000 / split);
......@@ -2587,6 +2594,9 @@ void nap_sleep(int ms, int split) {
if (input != got_user_input) {
break;
}
if (gd != got_local_pointer_input) {
break;
}
}
}
......@@ -2623,7 +2633,9 @@ static void nap_check(int tile_cnt) {
if (naptile && nap_ok && tile_cnt < naptile) {
int ms = napfac * waitms;
ms = ms > napmax ? napmax : ms;
if (now - last_input <= 2) {
if (now - last_input <= 3) {
nap_ok = 0;
} else if (now - last_local_input <= 3) {
nap_ok = 0;
} else {
nap_sleep(ms, 1);
......@@ -2942,11 +2954,15 @@ int scan_for_updates(int count_only) {
if (cmap8to24 && scan_count % 1 == 0) {
check_for_multivis();
}
#ifdef MACOSX
if (macosx_console) {
macosx_event_loop();
}
#endif
if (use_xdamage) {
/* first pass collecting DAMAGE events: */
#ifdef MACOSX
if (! dpy) {
macosx_event_loop();
if (macosx_console) {
collect_macosx_damage(-1, -1, -1, -1, 0);
} else
#endif
......@@ -2977,7 +2993,7 @@ int scan_for_updates(int count_only) {
*/
if (use_xdamage) {
#ifdef MACOSX
if (! dpy) {
if (macosx_console) {
;
} else
#endif
......
......@@ -867,7 +867,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
}
#ifdef MACOSX
if (raw_fb_addr != NULL && raw_fb_addr == macosx_get_fb_addr()) {
if (raw_fb_addr != NULL && macosx_console && raw_fb_addr == macosx_get_fb_addr()) {
raw_fb_addr = NULL;
}
#endif
......@@ -963,6 +963,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
raw_fb_fd = -1;
raw_fb_addr = NULL;
raw_fb_offset = 0;
raw_fb_bytes_per_line = 0;
last_mode = 0;
if (last_file) {
......@@ -1059,6 +1060,12 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
rfbLog("invalid rawfb str: %s\n", str);
clean_up_exit(1);
}
if (strrchr(q, '-')) {
char *q2 = strrchr(q, '-');
raw_fb_bytes_per_line = atoi(q2+1);
*q2 = '\0';
}
/* @WxHxB */
if (sscanf(q, "@%dx%dx%d", &w, &h, &b) != 3) {
rfbLogEnable(1);
......@@ -1145,11 +1152,13 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
q = strchr(str, ':');
q++;
macosx_console = 0;
if (strstr(q, "macosx:") == q) {
/* mmap:macosx:/dev/null@... */
q += strlen("macosx:");
do_macosx = 1;
do_mmap = 0;
macosx_console = 1;
}
last_file = strdup(q);
......@@ -1233,20 +1242,29 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
initialize_clipshift();
raw_fb = (char *) malloc(dpy_x * dpy_y * b/8);
if (raw_fb_bytes_per_line == 0) {
raw_fb_bytes_per_line = dpy_x*b/8;
/*
* Put cases here were we can determine that
* raw_bytes_per_line != dpy_x*b/8
*/
#ifdef MACOSX
if (do_macosx) {
raw_fb_bytes_per_line = macosxCG_CGDisplayBytesPerRow();
}
#endif
}
raw_fb_image->bytes_per_line = dpy_x * b/8;
raw_fb = (char *) malloc(dpy_y * dpy_x * b/8);
raw_fb_image->data = raw_fb;
raw_fb_image->format = ZPixmap;
raw_fb_image->width = dpy_x;
raw_fb_image->height = dpy_y;
raw_fb_image->bits_per_pixel = b;
raw_fb_image->bytes_per_line = dpy_x*b/8;
raw_fb_image->bitmap_unit = -1;
#ifdef MACOSX
if (do_macosx) {
raw_fb_image->bytes_per_line = macosxCG_CGDisplayBytesPerRow();
}
#endif
if (use_snapfb && (raw_fb_seek || raw_fb_mmap)) {
int b_use = b;
......@@ -1254,16 +1272,25 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
free(snap_fb);
}
if (b_use == 32 && xform24to32) {
/*
* The actual framebuffer (e.g. mapped addr) and
* snap fb must be the same bpp. E.g. both 24bpp.
* Reading FROM snap to utility image will be
* transformed 24->32 in copy_raw_fb_24_to_32.
*
* addr -> snap -> (scanline, fullscreen, ...)
*/
b_use = 24;
raw_fb_bytes_per_line = dpy_x * b_use/8;
}
snap_fb = (char *) malloc(dpy_x * dpy_y * b_use/8);
snap_fb = (char *) malloc(dpy_y * dpy_x * b_use/8);
snap = &ximage_struct_snap;
snap->data = snap_fb;
snap->format = ZPixmap;
snap->width = dpy_x;
snap->height = dpy_y;
snap->bits_per_pixel = b_use;
snap->bytes_per_line = dpy_x*b_use/8;
snap->bytes_per_line = dpy_x * b_use/8;
snap->bitmap_unit = -1;
}
......@@ -1334,11 +1361,11 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
}
if (clipshift) {
memset(raw_fb, 0xff, dpy_x * dpy_y * b/8);
memset(raw_fb, 0xff, dpy_y * raw_fb_image->bytes_per_line);
} else if (raw_fb_addr && ! xform24to32) {
memcpy(raw_fb, raw_fb_addr + raw_fb_offset, dpy_x*dpy_y*b/8);
memcpy(raw_fb, raw_fb_addr + raw_fb_offset, dpy_y * raw_fb_image->bytes_per_line);
} else {
memset(raw_fb, 0xff, dpy_x * dpy_y * b/8);
memset(raw_fb, 0xff, dpy_y * raw_fb_image->bytes_per_line);
}
if (verbose) {
......@@ -2275,6 +2302,8 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
rfb_bytes_per_line);
fprintf(stderr, " rot_fb_bytes_per_line: %d\n",
rot_bytes_per_line);
fprintf(stderr, " raw_fb_bytes_per_line: %d\n",
raw_fb_bytes_per_line);
switch(fb->format) {
case XYBitmap:
fprintf(stderr, " format: XYBitmap\n"); break;
......
......@@ -1537,6 +1537,9 @@ void unixpw_accept(char *user) {
unixpw_in_progress = 0;
unixpw_client = NULL;
mark_rect_as_modified(0, 0, dpy_x, dpy_y, 0);
if (macosx_console) {
refresh_screen(1);
}
}
void unixpw_deny(void) {
......
......@@ -97,12 +97,13 @@ int get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h,
unsigned int mask;
#ifdef MACOSX
if (! dpy) {
if (macosx_console) {
return macosx_get_wm_frame_pos(px, py, x, y, w, h, frame, win);
}
#endif
RAWFB_RET(0)
#if NO_X11
return 0;
#else
......@@ -2918,6 +2919,7 @@ if (db2) fprintf(stderr, "try_copyrect: 0x%lx bad: %d stack_list_num: %d\n", fr
sraRect rect;
int saw_me = 0;
int orig_x, orig_y;
int boff, bwin;
XWindowAttributes attr;
orig_x = x - dx;
......@@ -2935,6 +2937,9 @@ if (db2) fprintf(stderr, "moved_win: %4d %3d, %4d %3d 0x%lx ---\n",
dtime0(&tm);
boff = get_boff();
bwin = get_bwin();
X_LOCK;
/*
......@@ -2962,16 +2967,13 @@ fprintf(stderr, "bo: %d/%lx\n", k, swin);
#endif
/* skip some unwanted cases: */
#ifdef MACOSX
if (0) {
;
#else
#ifndef MACOSX
if (swin == None) {
continue;
}
if (swin < 10) {
; /* blackouts */
#endif
if (boff <= swin && swin < boff + bwin) {
; /* blackouts */
} else if (! stack_list[k].fetched ||
stack_list[k].time > tm + 2.0) {
if (!valid_window(swin, &attr, 1)) {
......@@ -3346,7 +3348,7 @@ int check_wireframe(void) {
int orig_px, orig_py, orig_x, orig_y, orig_w, orig_h;
int px, py, x, y, w, h;
int box_x, box_y, box_w, box_h;
int orig_cursor_x, orig_cursor_y, g;
int orig_cursor_x, orig_cursor_y, g, gd;
int already_down = 0, win_gone = 0, win_unmapped = 0;
double spin = 0.0, tm, last_ptr = 0.0, last_draw;
int frame_changed = 0, drew_box = 0, got_2nd_pointer = 0;
......@@ -3354,6 +3356,7 @@ int check_wireframe(void) {
static double first_dt_ave = 0.0;
static int first_dt_cnt = 0;
static time_t last_save_stacklist = 0;
int bdown0, bdown, gotui, cnt = 0;
/* heuristics: */
double first_event_spin = wireframe_t1;
......@@ -3363,25 +3366,47 @@ int check_wireframe(void) {
int try_it = 0;
DB_SET
#ifndef MACOSX
if (unixpw_in_progress) return 0;
#ifdef MACOSX
if (macosx_console) {
;
} else {
RAWFB_RET(0)
}
#else
RAWFB_RET(0)
#endif
if (unixpw_in_progress) return 0;
if (nofb) {
return 0;
}
if (subwin) {
return 0; /* don't even bother for -id case */
}
if (db > 1 && button_mask) fprintf(stderr, "check_wireframe: bm: %d gpi: %d\n", button_mask, got_pointer_input);
if (! button_mask) {
bdown0 = 0;
if (button_mask) {
bdown0 = 1;
} else if (wireframe_local && display_button_mask) {
bdown0 = 2;
}
if (! bdown0) {
return 0; /* no button pressed down */
}
if (!use_threads && !got_pointer_input) {
gotui = 0;
if (got_pointer_input) {
gotui = 1;
} else if (wireframe_local && display_button_mask) {
gotui = 2;
}
if (!use_threads && !gotui) {
return 0; /* need ptr input, e.g. button down, motion */
}
if (db > 1) fprintf(stderr, "check_wireframe: %d\n", db);
if (db) fprintf(stderr, "\n*** button down!! x: %d y: %d\n", cursor_x, cursor_y);
......@@ -3514,6 +3539,7 @@ if (db) fprintf(stderr, "INTERIOR\n");
}
g = got_pointer_input;
gd = got_local_pointer_input;
while (1) {
......@@ -3529,7 +3555,28 @@ if (db) fprintf(stderr, "INTERIOR\n");
} else {
rfbCFD(1000);
}
if (bdown0 == 2) {
int freq = 1;
/*
* This is to just update display_button_mask
* which will also update got_local_pointer_input.
*/
int px, py, x, y, w, h;
Window frame;
check_x11_pointer();
#if 0
#ifdef MACOSX
if (macosx_console) {
macosx_get_cursor_pos(&x, &y);
}
else
#endif
get_wm_frame_pos(&px, &py, &x, &y, &w, &h, &frame, NULL);
#endif
}
cnt++;
spin += dtime(&tm);
if (0) fprintf(stderr, "wf-spin: %.3f\n", spin);
......@@ -3575,12 +3622,15 @@ if (db || db2) fprintf(stderr, " SPIN-OUT-NO2ND_PTR: %.3f\n", spin);
break;
}
}
/* see if some pointer input occurred: */
if (got_pointer_input > g) {
if (db) fprintf(stderr, " ++pointer event!! [%02d] dt: %.3f x: %d y: %d mask: %d\n", got_2nd_pointer+1, spin, cursor_x, cursor_y, button_mask);
if (got_pointer_input > g ||
(wireframe_local && (got_local_pointer_input > gd))) {
if (db) fprintf(stderr, " ++pointer event!! [%02d] dt: %.3f x: %d y: %d mask: %d\n",
got_2nd_pointer+1, spin, cursor_x, cursor_y, button_mask);
g = got_pointer_input;
gd = got_local_pointer_input;
X_LOCK;
XFlush_wr(dpy);
......@@ -3716,7 +3766,13 @@ if (db) fprintf(stderr, "FRAME MOVE 1st-dt: %.3f\n", first_dt_ave/n);
* we check here to get a better location and size of
* the final window.
*/
if (! button_mask) {
bdown = 0;
if (button_mask) {
bdown = 1;
} else if (wireframe_local && display_button_mask) {
bdown = 2;
}
if (! bdown) {
if (db || db2) fprintf(stderr, "NO button_mask\n");
break_reason = 6;
break;
......@@ -4379,7 +4435,11 @@ static void check_user_input4(double dt, double dtr, int tile_diffs) {
int check_user_input(double dt, double dtr, int tile_diffs, int *cnt) {
#ifndef MACOSX
#ifdef MACOSX
if (! macosx_console) {
RAWFB_RET(0)
}
#else
RAWFB_RET(0)
#endif
......
......@@ -18,6 +18,8 @@ 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 *x, int *y);
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);
......@@ -78,11 +80,12 @@ int valid_window(Window win, XWindowAttributes *attr_ret, int bequiet) {
return 0;
}
#ifdef MACOSX
if (! dpy) {
if (macosx_console) {
return macosx_valid_window(win, attr_ret);
}
#endif
RAWFB_RET(0)
#if NO_X11
nox11_exit(1);
return 0;
......@@ -184,9 +187,14 @@ void snapshot_stack_list(int free_only, double allowed_age) {
stack_list_num = 0;
last_free = now;
#ifndef MACOSX
#ifdef MACOSX
if (! macosx_console) {
RAWFB_RET_VOID
}
#else
RAWFB_RET_VOID
#endif
#if NO_X11 && !defined(MACOSX)
return;
#else
......@@ -220,13 +228,7 @@ void snapshot_stack_list(int free_only, double allowed_age) {
j++;
}
for (i=0; i<blackouts; i++) {
#ifdef MACOSX
if (! dpy) {
num = num - blackouts;
break;
}
#endif
stack_list[j].win = 0x1;
stack_list[j].win = get_boff() + 1;
stack_list[j].fetched = 1;
stack_list[j].valid = 1;
stack_list[j].x = blackr[i].x1;
......@@ -255,10 +257,23 @@ if (0) fprintf(stderr, "blackr: %d %dx%d+%d+%d\n", i,
#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;
......@@ -268,11 +283,14 @@ void update_stack_list(void) {
}
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 && win < 10) {
if (win != None && boff <= win && win < boff + bwin) {
; /* special, blackout */
} else if (!valid_window(win, &attr, 1)) {
stack_list[k].valid = 0;
......@@ -302,6 +320,13 @@ Window query_pointer(Window start) {
Window r, c;
int rx, ry, wx, wy;
unsigned int mask;
#ifdef MACOSX
if (macosx_console) {
macosx_get_cursor_pos(&rx, &rx);
}
#endif
RAWFB_RET(None)
#if NO_X11
return None;
......
......@@ -15,6 +15,8 @@ extern Bool xtranslate(Window src, Window dst, int src_x, int src_y, int *dst_x,
int *dst_y, Window *child, int bequiet);
extern int get_window_size(Window win, int *x, int *y);
extern void snapshot_stack_list(int free_only, double allowed_age);
extern int get_boff(void);
extern int get_bwin(void);
extern void update_stack_list(void);
extern Window query_pointer(Window start);
extern unsigned int mask_state(void);
......
......@@ -2,7 +2,7 @@
.TH X11VNC "1" "November 2006" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
version: 0.8.4, lastmod: 2006-11-13
version: 0.8.4, lastmod: 2006-11-21
.SH SYNOPSIS
.B x11vnc
[OPTION]...
......@@ -977,7 +977,7 @@ override this.
.IP
Your VNC viewer will also need to be able to connect
via SSL. See the discussion below under \fB-stunnel\fR and
the FAQ (ssl_vncviewer script) for how this might be
the FAQ (ss_vncviewer script) for how this might be
achieved. E.g. on Unix it is easy to write a shell
script that starts up stunnel and then vncviewer.
Also in the x11vnc source a SSL enabled Java VNC Viewer
......@@ -1131,7 +1131,7 @@ key files. On the VNC client side, they will need to
be "imported" somehow. Web browsers have "Manage
Certificates" actions as does the Java applet plugin
Control Panel. stunnel can also use these files (see
the ssl_vncviewer example script in the FAQ.)
the ss_vncviewer example script in the FAQ.)
.PP
\fB-sslGenCA\fR \fI[dir]\fR
.IP
......@@ -1279,13 +1279,13 @@ Examples:
x11vnc \fB-sslGenCert\fR server
x11vnc \fB-ssl\fR SAVE \fB-display\fR :0 ...
.IP
and then on viewer using ssl_vncviewer stunnel wrapper
and then on viewer using ss_vncviewer stunnel wrapper
(see the FAQ):
ssl_vncviewer \fB-verify\fR ./cacert.crt hostname:0
ss_vncviewer \fB-verify\fR ./cacert.crt hostname:0
.IP
(this assumes the cacert.crt cert from \fB-sslGenCA\fR
was safely copied to the VNC viewer machine where
ssl_vncviewer is run)
ss_vncviewer is run)
.IP
Example using a name:
.IP
......@@ -1303,7 +1303,7 @@ x11vnc is then started with the the option \fB-sslverify\fR
roger), and on the viewer user on somehost could do
for example:
.IP
ssl_vncviewer \fB-mycert\fR ./roger.pem hostname:0
ss_vncviewer \fB-mycert\fR ./roger.pem hostname:0
.IP
If you set the env. var REQ_ARGS='...' it will be
passed to openssl
......@@ -2368,6 +2368,14 @@ between sending wireframe "animations". If a slow
link is detected, these values may be automatically
changed to something better for a slow link.
.PP
\fB-nowireframelocal\fR
.IP
By default, mouse motion and button presses of a
user sitting at the LOCAL display are monitored for
wireframing opportunities (so that the changes will be
sent efficiently to the VNC clients). Use this option
to disable this behavior.
.PP
\fB-wirecopyrect\fR \fImode,\fR \fB-nowirecopyrect\fR
.IP
Since the \fB-wireframe\fR mechanism evidently tracks moving
......@@ -2864,6 +2872,31 @@ manpage
for details. \fB-nofbpm\fR is basically the same as running
"xset fbpm force on" periodically. Default: \fB-fbpm\fR
.PP
\fB-nodpms,\fR \fB-dpms\fR
.IP
If the system supports the DPMS (Display Power Management
Signaling) extension, then prevent the monitor from
going into a reduced power state when VNC clients
are connected.
.IP
DPMS reduced power monitor states are a good thing
and you normally want the power down to take place
(usually x11vnc has no problem exporting the display in
this state). You probably only want to use "\fB-nodpms\fR"
to work around problems with Screen Savers kicking
on in DPMS low power states. There is known problem
with kdesktop_lock on KDE where the screen saver keeps
kicking in every time user input stops for a second
or two. Specifying "\fB-nodpms\fR" works around it.
.IP
"\fB-nodpms\fR" means prevent DPMS low power states whenever
VNC clients are connected, while "\fB-dpms\fR" means to not
monitor the DPMS state at all. See the
.IR xset (1)
manpage
for details. \fB-nodpms\fR is basically the same as running
"xset dpms force on" periodically. Default: \fB-dpms\fR
.PP
\fB-noxdamage\fR
.IP
Do not use the X DAMAGE extension to detect framebuffer
......@@ -3012,6 +3045,11 @@ red, green, and blue masks and an offset into the
memory object. If the masks are not provided x11vnc
guesses them based on the bpp.
.IP
Another optional suffix is the Bytes Per Line which in
some cases is not WxHxB/4. Specify it as WxHxB-BPL
e.g. 800x600x16-2048. This could be a normal width
1024 at 16bpp fb, but only width 800 shows up.
.IP
Examples:
.IP
\fB-rawfb\fR shm:210337933@800x600x32:ff/ff00/ff0000
......@@ -3343,6 +3381,27 @@ For the native Mac OS X server, disable display sleep.
.IP
For the native Mac OS X server, disable screensaver.
.PP
\fB-macnowait\fR
.IP
For the native Mac OS X server, do not wait for the
user to switch back to his display.
.PP
\fB-macwheel\fR \fIn\fR
.IP
For the native Mac OS X server, set the mouse wheel
speed to n (default 5).
.PP
\fB-macnoswap\fR
.IP
For the native Mac OS X server, do not swap mouse
buttons 2 and 3.
.PP
\fB-macnoresize\fR
.IP
For the native Mac OS X server, do not resize or reset
the framebuffer even if it is detected that the screen
resolution or depth has changed.
.PP
\fB-gui\fR \fI[gui-opts]\fR
.IP
Start up a simple tcl/tk gui based on the the remote
......@@ -3795,6 +3854,10 @@ wireframe:str enable \fB-wireframe\fR mode string.
.IP
wireframe_mode:str enable \fB-wireframe\fR mode string.
.IP
wireframelocal enable wireframelocal. same as "wfl"
.IP
nowireframe disable wireframelocal. same as "nowfl"
.IP
wirecopyrect:str set \fB-wirecopyrect\fR string. same as "wcr:"
.IP
scrollcopyrect:str set \fB-scrollcopyrect\fR string. same "scr"
......@@ -3869,6 +3932,10 @@ fbpm disable \fB-nofbpm\fR mode.
.IP
nofbpm enable \fB-nofbpm\fR mode.
.IP
dpms disable \fB-nodpms\fR mode.
.IP
nodpms enable \fB-nodpms\fR mode.
.IP
xdamage enable xdamage polling hints.
.IP
noxdamage disable xdamage polling hints.
......@@ -4026,35 +4093,36 @@ unlock connect allowonce allow localhost nolocalhost
listen lookup nolookup accept afteraccept gone shm
noshm flipbyteorder noflipbyteorder onetile noonetile
solid_color solid nosolid blackout xinerama noxinerama
xtrap noxtrap xrandr noxrandr xrandr_mode rotate
padgeom quiet q noquiet modtweak nomodtweak xkb noxkb
capslock nocapslock skip_lockkeys noskip_lockkeys
skip_keycodes sloppy_keys nosloppy_keys skip_dups
noskip_dups add_keysyms noadd_keysyms clear_mods
noclear_mods clear_keys noclear_keys remap repeat
norepeat fb nofb bell nobell sel nosel primary
noprimary setprimary nosetprimary clipboard noclipboard
setclipboard nosetclipboard seldir cursorshape
nocursorshape cursorpos nocursorpos cursor_drag
nocursor_drag cursor show_cursor noshow_cursor
nocursor arrow xfixes noxfixes xdamage noxdamage
xd_area xd_mem alphacut alphafrac alpharemove
noalpharemove alphablend noalphablend xwarppointer
xwarp noxwarppointer noxwarp buttonmap dragging
nodragging wireframe_mode wireframe wf nowireframe
nowf wirecopyrect wcr nowirecopyrect nowcr scr_area
xtrap noxtrap xrandr noxrandr xrandr_mode rotate padgeom
quiet q noquiet modtweak nomodtweak xkb noxkb capslock
nocapslock skip_lockkeys noskip_lockkeys skip_keycodes
sloppy_keys nosloppy_keys skip_dups noskip_dups
add_keysyms noadd_keysyms clear_mods noclear_mods
clear_keys noclear_keys remap repeat norepeat fb nofb
bell nobell sel nosel primary noprimary setprimary
nosetprimary clipboard noclipboard setclipboard
nosetclipboard seldir cursorshape nocursorshape
cursorpos nocursorpos cursor_drag nocursor_drag cursor
show_cursor noshow_cursor nocursor arrow xfixes noxfixes
xdamage noxdamage xd_area xd_mem alphacut alphafrac
alpharemove noalpharemove alphablend noalphablend
xwarppointer xwarp noxwarppointer noxwarp buttonmap
dragging nodragging wireframe_mode wireframe wf
nowireframe nowf wireframelocal wfl nowireframelocal
nowfl wirecopyrect wcr nowirecopyrect nowcr scr_area
scr_skip scr_inc scr_keys scr_term scr_keyrepeat
scr_parms scrollcopyrect scr noscrollcopyrect noscr
fixscreen noxrecord xrecord reset_record pointer_mode pm
input_skip allinput noallinput input grabkbd nograbkbd
grabptr nograbptr client_input ssltimeout speeds wmdt
debug_pointer dp nodebug_pointer nodp debug_keyboard
dk nodebug_keyboard nodk deferupdate defer wait_ui
wait_bog nowait_bog slow_fb wait readtimeout nap nonap
sb screen_blank fbpm nofbpm fs gaps grow fuzz snapfb
nosnapfb rawfb uinput_accel uinput_thresh uinput_reset
uinput_always progressive rfbport http nohttp httpport
httpdir enablehttpproxy noenablehttpproxy alwaysshared
fixscreen noxrecord xrecord reset_record pointer_mode
pm input_skip allinput noallinput input grabkbd
nograbkbd grabptr nograbptr client_input ssltimeout
speeds wmdt debug_pointer dp nodebug_pointer nodp
debug_keyboard dk nodebug_keyboard nodk deferupdate
defer wait_ui wait_bog nowait_bog slow_fb wait
readtimeout nap nonap sb screen_blank fbpm nofbpm
dpms nodpms fs gaps grow fuzz snapfb nosnapfb rawfb
uinput_accel uinput_thresh uinput_reset uinput_always
progressive rfbport http nohttp httpport httpdir
enablehttpproxy noenablehttpproxy alwaysshared
noalwaysshared nevershared noalwaysshared dontdisconnect
nodontdisconnect desktop debug_xevents nodebug_xevents
debug_xevents debug_xdamage nodebug_xdamage
......
......@@ -452,6 +452,7 @@ static void watch_loop(void) {
got_user_input = 0;
got_pointer_input = 0;
got_local_pointer_input = 0;
got_pointer_calls = 0;
got_keyboard_input = 0;
got_keyboard_calls = 0;
......@@ -558,14 +559,14 @@ static void watch_loop(void) {
check_pm();
check_filexfer();
check_keycode_state();
check_connect_inputs();
check_gui_inputs();
check_stunnel();
check_openssl();
check_https();
check_connect_inputs();
check_gui_inputs();
check_stunnel();
check_openssl();
check_https();
record_last_fb_update();
check_padded_fb();
check_fixscreen();
check_padded_fb();
check_fixscreen();
check_xdamage_state();
check_xrecord_reset(0);
check_add_keysyms();
......@@ -602,6 +603,9 @@ static void watch_loop(void) {
if (cursor_pos_updates) {
check_x11_pointer();
}
#ifdef MACOSX
else check_x11_pointer();
#endif
continue;
}
......@@ -1236,6 +1240,7 @@ static void print_settings(int try_http, int bg, char *gui_str) {
fprintf(stderr, " take_naps: %d\n", take_naps);
fprintf(stderr, " sb: %d\n", screen_blank);
fprintf(stderr, " fbpm: %d\n", !watch_fbpm);
fprintf(stderr, " dpms: %d\n", !watch_dpms);
fprintf(stderr, " xdamage: %d\n", use_xdamage);
fprintf(stderr, " xd_area: %d\n", xdamage_max_area);
fprintf(stderr, " xd_mem: %.3f\n", xdamage_memory);
......@@ -1263,7 +1268,6 @@ static void print_settings(int try_http, int bg, char *gui_str) {
fprintf(stderr, " pid: %d\n", getpid());
fprintf(stderr, "\n");
#endif
rfbLog("x11vnc version: %s\n", lastmod);
}
......@@ -2101,6 +2105,9 @@ int main(int argc, char* argv[]) {
} else if (!strcmp(arg, "-nowireframe")
|| !strcmp(arg, "-nowf")) {
wireframe = 0;
} else if (!strcmp(arg, "-nowireframelocal")
|| !strcmp(arg, "-nowfl")) {
wireframe_local = 0;
} else if (!strcmp(arg, "-wirecopyrect")
|| !strcmp(arg, "-wcr")) {
CHECK_ARGC
......@@ -2219,6 +2226,10 @@ int main(int argc, char* argv[]) {
watch_fbpm = 1;
} else if (!strcmp(arg, "-fbpm")) {
watch_fbpm = 0;
} else if (!strcmp(arg, "-nodpms")) {
watch_dpms = 1;
} else if (!strcmp(arg, "-dpms")) {
watch_dpms = 0;
} else if (!strcmp(arg, "-xdamage")) {
use_xdamage = 1;
} else if (!strcmp(arg, "-noxdamage")) {
......@@ -2292,6 +2303,15 @@ int main(int argc, char* argv[]) {
macosx_nosleep = 1;
} else if (!strcmp(arg, "-macnosaver")) {
macosx_noscreensaver = 1;
} else if (!strcmp(arg, "-macnowait")) {
macosx_wait_for_switch = 0;
} else if (!strcmp(arg, "-macwheel")) {
CHECK_ARGC
macosx_mouse_wheel_speed = atoi(argv[++i]);
} else if (!strcmp(arg, "-macnoswap")) {
macosx_swap23 = 0;
} else if (!strcmp(arg, "-macnoresize")) {
macosx_resize = 0;
} else if (!strcmp(arg, "-gui")) {
launch_gui = 1;
if (i < argc-1) {
......@@ -2910,6 +2930,7 @@ int main(int argc, char* argv[]) {
if (verbose) {
print_settings(try_http, bg, gui_str);
}
rfbLog("x11vnc version: %s\n", lastmod);
} else {
rfbLogEnable(0);
}
......@@ -3390,13 +3411,16 @@ int main(int argc, char* argv[]) {
#ifdef MACOSX
if (! dpy) {
if (! multiple_cursors_mode) {
multiple_cursors_mode = strdup("most");
}
initialize_cursors_mode();
if (use_xdamage) {
xdamage_present = 1;
initialize_xdamage();
/* XXX this needs improvement (esp. for remote control) */
if (! raw_fb_str || strstr(raw_fb_str, "console") == raw_fb_str) {
if (! multiple_cursors_mode) {
multiple_cursors_mode = strdup("most");
}
initialize_cursors_mode();
if (use_xdamage) {
xdamage_present = 1;
initialize_xdamage();
}
}
}
#endif
......@@ -3460,6 +3484,9 @@ int main(int argc, char* argv[]) {
rfbLog("waited_for_client: popup accepted.\n");
cl0->onHold = FALSE;
}
if (macosx_console) {
refresh_screen(1);
}
}
if (! waited_for_client) {
......
......@@ -360,6 +360,9 @@ extern int button_mask; /* button state and info */
extern int button_mask_prev;
extern int num_buttons;
extern unsigned int display_button_mask;
extern unsigned int display_mod_mask;
/* image structures */
extern XImage *scanline;
extern XImage *fullscreen;
......@@ -411,6 +414,8 @@ extern unsigned long main_red_mask, main_green_mask, main_blue_mask;
extern unsigned short main_red_max, main_green_max, main_blue_max;
extern unsigned short main_red_shift, main_green_shift, main_blue_shift;
extern int raw_fb_bytes_per_line; /* of actual raw region we poll, not our raw_fb */
/* scaling parameters */
extern char *scale_str;
extern double scale_fac;
......@@ -446,6 +451,7 @@ extern unsigned char *tile_has_xdamage_diff, *tile_row_has_xdamage_diff;
/* times of recent events */
extern time_t last_event, last_input, last_client;
extern time_t last_keyboard_input, last_pointer_input;
extern time_t last_local_input;
extern time_t last_fb_bytes_sent;
extern double last_keyboard_time;
extern double last_pointer_time;
......@@ -471,6 +477,7 @@ extern int cursor_x, cursor_y; /* x and y from the viewer(s) */
extern int button_change_x, button_change_y;
extern int got_user_input;
extern int got_pointer_input;
extern int got_local_pointer_input;
extern int got_pointer_calls;
extern int got_keyboard_input;
extern int got_keyboard_calls;
......
......@@ -15,7 +15,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.8.4 lastmod: 2006-11-13";
char lastmod[] = "0.8.4 lastmod: 2006-11-21";
/* X display info */
......@@ -36,6 +36,9 @@ int button_mask = 0; /* button state and info */
int button_mask_prev = 0;
int num_buttons = -1;
unsigned int display_button_mask = 0;
unsigned int display_mod_mask = 0;
/* image structures */
XImage *scanline = NULL;
XImage *fullscreen = NULL;
......@@ -77,6 +80,8 @@ unsigned long main_red_mask = 0, main_green_mask = 0, main_blue_mask = 0;
unsigned short main_red_max = 0, main_green_max = 0, main_blue_max = 0;
unsigned short main_red_shift = 0, main_green_shift = 0, main_blue_shift = 0;
int raw_fb_bytes_per_line = 0;
/* scaling parameters */
char *scale_str = NULL;
double scale_fac = 1.0;
......@@ -111,6 +116,7 @@ unsigned char *tile_has_xdamage_diff = NULL, *tile_row_has_xdamage_diff = NULL;
/* times of recent events */
time_t last_event, last_input = 0, last_client = 0;
time_t last_local_input = 0;
time_t last_keyboard_input = 0, last_pointer_input = 0;
time_t last_fb_bytes_sent = 0;
double last_keyboard_time = 0.0;
......@@ -137,6 +143,7 @@ int cursor_x = 0, cursor_y = 0; /* x and y from the viewer(s) */
int button_change_x = 0, button_change_y = 0;
int got_user_input = 0;
int got_pointer_input = 0;
int got_local_pointer_input = 0;
int got_pointer_calls = 0;
int got_keyboard_input = 0;
int got_keyboard_calls = 0;
......
......@@ -163,8 +163,8 @@ void add_region_xdamage(sraRegionPtr new_region) {
}
reg = xdamage_regions[prev_tick];
if (reg != NULL) {
if (debug_xdamage > 1) fprintf(stderr, "add_region_xdamage: prev_tick: %d reg %p\n", prev_tick, (void *)reg);
if (reg != NULL && new_region != NULL) {
if (debug_xdamage > 1) fprintf(stderr, "add_region_xdamage: prev_tick: %d reg %p new_region %p\n", prev_tick, (void *)reg, (void *)new_region);
sraRgnOr(reg, new_region);
}
}
......@@ -232,6 +232,9 @@ if (call && debug_xdamage > 1) fprintf(stderr, "collect_macosx_damage: %d %d %d
if (! use_xdamage) {
return 0;
}
if (! xdamage_regions) {
return 0;
}
dtime0(&tm);
......@@ -241,10 +244,15 @@ if (call && debug_xdamage > 1) fprintf(stderr, "collect_macosx_damage: %d %d %d
xdamage_ticker = (xdamage_ticker+1) % nreg;
xdamage_direct_count = 0;
reg = xdamage_regions[xdamage_ticker];
sraRgnMakeEmpty(reg);
if (reg != NULL) {
sraRgnMakeEmpty(reg);
}
} else {
reg = xdamage_regions[xdamage_ticker];
}
if (reg == NULL) {
return 0;
}
if (x_in < 0) {
return 0;
......@@ -288,8 +296,8 @@ if (call && debug_xdamage > 1) fprintf(stderr, "collect_macosx_damage: %d %d %d
}
if (debug_xdamage > 2) {
fprintf(stderr, "xdamage: -> event %dx%d+%d+%d area:"
" %d dups: %d %s\n", w, h, x, y, w*h, dcount,
(w*h > xdamage_max_area) ? "TOO_BIG" : "");
" %d dups: %d %s reg: %p\n", w, h, x, y, w*h, dcount,
(w*h > xdamage_max_area) ? "TOO_BIG" : "", (void *)reg);
}
record_desired_xdamage_rect(x, y, w, h);
......@@ -365,6 +373,9 @@ int collect_xdamage(int scancnt, int call) {
if (! xdamage_base_event_type) {
return 0;
}
if (! xdamage_regions) {
return 0;
}
dtime0(&tm);
......@@ -374,10 +385,15 @@ int collect_xdamage(int scancnt, int call) {
xdamage_ticker = (xdamage_ticker+1) % nreg;
xdamage_direct_count = 0;
reg = xdamage_regions[xdamage_ticker];
sraRgnMakeEmpty(reg);
if (reg != NULL) {
sraRgnMakeEmpty(reg);
}
} else {
reg = xdamage_regions[xdamage_ticker];
}
if (reg == NULL) {
return 0;
}
X_LOCK;
......@@ -549,6 +565,9 @@ int xdamage_hint_skip(int y) {
/* go back thru the history starting at most recent */
n = (xdamage_ticker + nreg - i) % nreg;
reg = xdamage_regions[n];
if (reg == NULL) {
continue;
}
if (sraRgnEmpty(reg)) {
/* checking for emptiness is very fast */
continue;
......
......@@ -13,6 +13,7 @@
#include "connections.h"
#include "unixpw.h"
#include "cleanup.h"
#include "macosx.h"
/* XXX CHECK BEFORE RELEASE */
int grab_buster = 0;
......@@ -639,11 +640,10 @@ void check_keycode_state(void) {
if (! client_count) {
return;
}
if (unixpw_in_progress) return;
RAWFB_RET_VOID
if (unixpw_in_progress) return;
/*
* periodically update our model of the keycode_state[]
* by correlating with the Xserver. wait for a pause in
......@@ -744,13 +744,13 @@ void check_xevents(int reset) {
static double last_request = 0.0;
XErrorHandler old_handler;
if (unixpw_in_progress) return;
RAWFB_RET_VOID
#if NO_X11
return;
#else
if (unixpw_in_progress) return;
if (now > last_init_check+1 || reset) {
last_init_check = now;
initialize_xevents(reset);
......@@ -1119,11 +1119,6 @@ void check_xevents(int reset) {
void xcut_receive(char *text, int len, rfbClientPtr cl) {
allowed_input_t input;
RAWFB_RET_VOID
#if NO_X11
return;
#else
if (unixpw_in_progress) {
rfbLog("xcut_receive: unixpw_in_progress, skipping.\n");
return;
......@@ -1147,6 +1142,18 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
return;
}
#ifdef MACOSX
if (macosx_console) {
return macosx_set_sel(text, len);
}
#endif
RAWFB_RET_VOID
#if NO_X11
return;
#else
X_LOCK;
/* associate this text with PRIMARY (and SECONDARY...) */
......
......@@ -385,6 +385,7 @@ static void copy_raw_fb_24_to_32(XImage *dest, int x, int y, unsigned int w,
} else if (! raw_fb_seek) {
/* mmap */
bpl = raw_fb_bytes_per_line;
src = raw_fb_addr + raw_fb_offset + bpl*y + 3*x;
dst = dest->data;
......@@ -408,7 +409,9 @@ static void copy_raw_fb_24_to_32(XImage *dest, int x, int y, unsigned int w,
} else {
/* lseek */
off_t off = (off_t) (raw_fb_offset + bpl*y + 3*x);
off_t off;
bpl = raw_fb_bytes_per_line;
off = (off_t) (raw_fb_offset + bpl*y + 3*x);
lseek(raw_fb_fd, off, SEEK_SET);
dst = dest->data;
......@@ -478,6 +481,7 @@ void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) {
} else if (! raw_fb_seek) {
/* mmap */
bpl = raw_fb_bytes_per_line;
src = raw_fb_addr + raw_fb_offset + bpl*y + pixelsize*x;
dst = dest->data;
......@@ -490,7 +494,9 @@ void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) {
} else {
/* lseek */
int n, len, del, sz = w * pixelsize;
off_t off = (off_t) (raw_fb_offset + bpl*y + pixelsize*x);
off_t off;
bpl = raw_fb_bytes_per_line;
off = (off_t) (raw_fb_offset + bpl*y + pixelsize*x);
lseek(raw_fb_fd, off, SEEK_SET);
dst = dest->data;
......@@ -1063,9 +1069,18 @@ int XCloseDisplay_wr(Display *display) {
#endif /* NO_X11 */
}
static unsigned int Bmask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
static unsigned int Mmask = (ShiftMask|LockMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask);
static unsigned int last_local_button_mask = 0;
static unsigned int last_local_mod_mask = 0;
static int last_local_x = 0;
static int last_local_y = 0;
Bool XQueryPointer_wr(Display *display, Window w, Window *root_return,
Window *child_return, int *root_x_return, int *root_y_return,
int *win_x_return, int *win_y_return, unsigned int *mask_return) {
Bool rc;
#if NO_X11
return False;
......@@ -1073,9 +1088,24 @@ Bool XQueryPointer_wr(Display *display, Window w, Window *root_return,
if (! display) {
return False;
}
return XQueryPointer(display, w, root_return, child_return,
rc = XQueryPointer(display, w, root_return, child_return,
root_x_return, root_y_return, win_x_return, win_y_return,
mask_return);
if (rc) {
display_button_mask = (*mask_return) & Bmask;
display_mod_mask = (*mask_return) & Mmask;
if (last_local_button_mask != display_button_mask) {
got_local_pointer_input++;
} else if (*root_x_return != last_local_x ||
*root_y_return != last_local_y) {
got_local_pointer_input++;
}
last_local_button_mask = display_button_mask;
last_local_mod_mask = display_mod_mask;
last_local_x = *root_x_return;
last_local_y = *root_y_return;
}
return rc;
#endif /* NO_X11 */
}
......@@ -1085,7 +1115,7 @@ Status XQueryTree_wr(Display *display, Window w, Window *root_return,
unsigned int *nchildren_return) {
#ifdef MACOSX
if (! display) {
if (macosx_console) {
return macosx_xquerytree(w, root_return, parent_return,
children_return, nchildren_return);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment