00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <sys/time.h>
00026 #include <gdk/gdkwindow.h>
00027 #include <gdk/gdkx.h>
00028 #include <gtk/gtk.h>
00029 #include <libbonobo.h>
00030 #include "magnifier.h"
00031 #include "magnifier-private.h"
00032 #include "zoom-region.h"
00033 #include "GNOME_Magnifier.h"
00034
00035 #define ENV_STRING_MAX_SIZE 128
00036
00037 GNOME_Magnifier_ZoomRegion zoom_region;
00038
00039 typedef struct {
00040 gchar *target_display;
00041 gchar *source_display;
00042 gchar *cursor_set;
00043 gchar *smoothing_type;
00044 float zoom_factor;
00045 float zoom_factor_x;
00046 float zoom_factor_y;
00047 int refresh_time;
00048 int mouse_poll_time;
00049 int cursor_size;
00050 float cursor_scale_factor;
00051 guint32 cursor_color;
00052 int vertical_split;
00053 int horizontal_split;
00054 int fullscreen;
00055 int mouse_follow;
00056 int invert_image;
00057 int no_initial_region;
00058 int timing_iterations;
00059 int timing_output;
00060 int timing_delta_x;
00061 int timing_delta_y;
00062 int timing_pan_rate;
00063 int smooth_scroll;
00064 int border_width;
00065 unsigned long border_color;
00066 int test_pattern;
00067 int is_override_redirect;
00068 int ignore_damage;
00069 } MagnifierOptions;
00070
00071 static MagnifierOptions global_options = { NULL,
00072 NULL,
00073 "default",
00074 "none",
00075 2.0,
00076 0.0,
00077 0.0,
00078 500,
00079 50,
00080 0,
00081 0.0F,
00082 0xFF000000,
00083 0,
00084 0,
00085 0,
00086 0,
00087 0,
00088 0,
00089 0,
00090 0,
00091 10,
00092 10,
00093 0,
00094 1,
00095 0,
00096 0,
00097 0,
00098 0,
00099 0
00100 };
00101
00102 static GOptionEntry magnifier_options [] = {
00103 {"target-display", 't', 0, G_OPTION_ARG_STRING, &global_options.target_display, "specify display on which to show magnified view", NULL},
00104 {"source-display", 's', 0, G_OPTION_ARG_STRING, &global_options.source_display, "specify display to magnify", NULL},
00105 {"cursor-set", 0, 0, G_OPTION_ARG_STRING, &global_options.cursor_set, "cursor set to use in target display", NULL},
00106 {"cursor-size", 0, 0, G_OPTION_ARG_INT, &global_options.cursor_size, "cursor size to use (overrides cursor-scale-factor)", NULL},
00107 {"cursor-scale-factor", 0, 0, G_OPTION_ARG_DOUBLE, &global_options.cursor_scale_factor, "cursor scale factor", NULL},
00108 {"cursor-color", 0, 0, G_OPTION_ARG_INT64, &global_options.cursor_color, "cursor color (applied to \'black\' pixels)", NULL},
00109 {"vertical", 'v', 0, G_OPTION_ARG_NONE, &global_options.vertical_split, "split screen vertically (if target display = source display)", NULL},
00110 {"horizontal", 'h', 0, G_OPTION_ARG_NONE, &global_options.horizontal_split, "split screen horizontally (if target display = source display)", NULL},
00111 {"mouse-follow", 'm', 0, G_OPTION_ARG_NONE, &global_options.mouse_follow, "track mouse movements", NULL},
00112 {"refresh-time", 'r', 0, G_OPTION_ARG_INT, &global_options.refresh_time, "minimum refresh time for idle, in ms", NULL},
00113 {"mouse-latency", 0, 0, G_OPTION_ARG_INT, &global_options.mouse_poll_time, "maximum mouse latency time, in ms", NULL},
00114 {"zoom-factor", 'z', 0, G_OPTION_ARG_DOUBLE, &global_options.zoom_factor, "zoom (scale) factor used to magnify source display", NULL},
00115 {"invert-image", 'i', 0, G_OPTION_ARG_NONE, &global_options.invert_image, "invert the image colormap", NULL},
00116 {"no-initial-region", 0, 0, G_OPTION_ARG_NONE, &global_options.no_initial_region, "don't create an initial zoom region", NULL},
00117 {"timing-iterations", 0, 0, G_OPTION_ARG_INT, &global_options.timing_iterations, "iterations to run timing benchmark test (0=continuous)", NULL},
00118 {"timing-output", 0, 0, G_OPTION_ARG_NONE, &global_options.timing_output, "display performance ouput", NULL},
00119 {"timing-pan-rate", 0, 0, G_OPTION_ARG_INT, &global_options.timing_pan_rate, "timing pan rate in lines per frame", NULL},
00120 {"timing-delta-x", 0, 0, G_OPTION_ARG_INT, &global_options.timing_delta_x, "pixels to pan in x-dimension each frame in timing update test", NULL},
00121 {"timing-delta-y", 0, 0, G_OPTION_ARG_INT, &global_options.timing_delta_y, "pixels to pan in y-dimension each frame in timing update test", NULL},
00122 {"smoothing-type", 0, 0, G_OPTION_ARG_STRING, &global_options.smoothing_type, "image smoothing algorithm to apply (bilinear-interpolation | none)", NULL},
00123 {"fullscreen", 'f', 0, G_OPTION_ARG_NONE, &global_options.fullscreen, "fullscreen magnification, covers entire target display [REQUIRES --source-display and --target-display]", NULL},
00124 {"smooth-scrolling", 0, 0, G_OPTION_ARG_NONE, &global_options.smooth_scroll, "use smooth scrolling", NULL},
00125 {"border-size", 'b', 0, G_OPTION_ARG_INT, &global_options.border_width, "width of border", NULL},
00126 {"border-color", 'c', 0, G_OPTION_ARG_INT64, &global_options.border_color, "border color specified as (A)RGB 23-bit value, Alpha-MSB", NULL},
00127 {"use-test-pattern", 0, 0, G_OPTION_ARG_NONE, &global_options.test_pattern, "use test pattern as source", NULL},
00128 {"override-redirect", 0, 0, G_OPTION_ARG_NONE, &global_options.is_override_redirect, "make the magnifier window totally unmanaged by the window manager", NULL},
00129 {"ignore-damage", 0, 0, G_OPTION_ARG_NONE, &global_options.ignore_damage, "ignore the X server DAMAGE extension, if present", NULL},
00130 {NULL}
00131 };
00132
00133 static void
00134 init_rect_bounds (GNOME_Magnifier_RectBounds *bounds,
00135 long x1, long y1, long x2, long y2)
00136 {
00137 bounds->x1 = x1;
00138 bounds->y1 = y1;
00139 bounds->x2 = x2;
00140 bounds->y2 = y2;
00141 }
00142
00143 static int screen_width, screen_height;
00144
00145 static int
00146 magnifier_main_test_image (gpointer data)
00147 {
00148 static long timing_counter = 0;
00149 static int timing_x_pos = 0;
00150 static int timing_y_pos = 0;
00151 static int x_direction = 1;
00152 static int y_direction = 1;
00153 Magnifier *magnifier = (Magnifier *) data;
00154 GNOME_Magnifier_ZoomRegionList *zoom_regions;
00155 Bonobo_PropertyBag properties;
00156 CORBA_Environment ev;
00157 GNOME_Magnifier_RectBounds roi;
00158 int x_roi, y_roi;
00159
00160
00161 if (global_options.timing_iterations > 0) {
00162 if (timing_counter > global_options.timing_iterations) {
00163 CORBA_exception_init (&ev);
00164 properties = GNOME_Magnifier_ZoomRegion_getProperties (zoom_region, &ev);
00165 if (BONOBO_EX (&ev))
00166 fprintf (stderr, "EXCEPTION\n");
00167
00168 bonobo_pbclient_set_boolean (properties, "exit-magnifier",
00169 TRUE, &ev);
00170 }
00171 }
00172
00173 CORBA_exception_init (&ev);
00174
00175 x_roi = global_options.timing_delta_x * timing_x_pos;
00176 roi.x1 = x_roi;
00177 roi.x2 = (screen_width / global_options.zoom_factor) + roi.x1;
00178 x_roi = global_options.timing_delta_x * (timing_x_pos + x_direction);
00179
00180
00181 if (x_roi + (screen_width / global_options.zoom_factor) > screen_width)
00182 x_direction = -1;
00183 else if (x_roi < 0)
00184 x_direction = 1;
00185
00186 timing_x_pos += x_direction;
00187
00188 y_roi = global_options.timing_delta_y * timing_y_pos;
00189
00190
00191 if (global_options.horizontal_split)
00192 roi.y1 = y_roi + screen_height;
00193 else
00194 roi.y1 = y_roi;
00195 roi.y2 = (screen_height / global_options.zoom_factor) + roi.y1;
00196
00197 y_roi = global_options.timing_delta_y * (timing_y_pos + y_direction);
00198
00199
00200 if (y_roi + (screen_height / global_options.zoom_factor) > screen_height) {
00201 timing_counter++;
00202 y_direction = -1;
00203 }
00204 else if (y_roi < 0) {
00205 timing_counter++;
00206 y_direction = 1;
00207 }
00208
00209 timing_y_pos += y_direction;
00210
00211 if (!IS_MAGNIFIER (magnifier))
00212 return FALSE;
00213
00214 magnifier->priv->cursor_x = (roi.x2 + roi.x1) / 2;
00215 magnifier->priv->cursor_y = (roi.y2 + roi.y1) / 2;
00216
00217 zoom_regions =
00218 GNOME_Magnifier_Magnifier_getZoomRegions (
00219 BONOBO_OBJREF (magnifier),
00220 &ev);
00221
00222 if (zoom_regions && (zoom_regions->_length > 0)) {
00223
00224 GNOME_Magnifier_ZoomRegion_setROI (
00225 zoom_regions->_buffer[0], &roi, &ev);
00226 }
00227
00228 return TRUE;
00229 }
00230
00231 static int last_x = 0, last_y = 0;
00232
00233 static int
00234 magnifier_main_pan_image (gpointer data)
00235 {
00236 Magnifier *magnifier = (Magnifier *) data;
00237 GNOME_Magnifier_ZoomRegionList *zoom_regions;
00238 GNOME_Magnifier_ZoomRegion zoom_region;
00239 CORBA_Environment ev;
00240 GNOME_Magnifier_RectBounds roi;
00241 int mouse_x_return, mouse_y_return;
00242 int w, h;
00243 GdkModifierType mask_return;
00244
00245 CORBA_exception_init (&ev);
00246
00247 if (global_options.mouse_follow && IS_MAGNIFIER (magnifier))
00248 {
00249 gdk_window_get_pointer (
00250 magnifier_get_root (magnifier),
00251 &mouse_x_return,
00252 &mouse_y_return,
00253 &mask_return);
00254
00255 if (last_x != mouse_x_return || last_y != mouse_y_return)
00256 {
00257 last_x = mouse_x_return;
00258 last_y = mouse_y_return;
00259 w = (magnifier->target_bounds.x2 - magnifier->target_bounds.x1);
00260 h = (magnifier->target_bounds.y2 - magnifier->target_bounds.y1);
00261 roi.x1 = mouse_x_return;
00262 roi.y1 = mouse_y_return;
00263 roi.x2 = roi.x1 + 1;
00264 roi.y2 = roi.y1 + 1;
00265
00266 zoom_regions =
00267 GNOME_Magnifier_Magnifier_getZoomRegions (
00268 BONOBO_OBJREF (magnifier),
00269 &ev);
00270 if (zoom_regions && (zoom_regions->_length > 0))
00271 {
00272 int i;
00273 for (i = 0; i < zoom_regions->_length; ++i)
00274 {
00275
00276 zoom_region =
00277 CORBA_Object_duplicate (
00278 ( (CORBA_Object *)
00279 (zoom_regions->_buffer))[i], &ev);
00280 if (zoom_region != CORBA_OBJECT_NIL) {
00281 GNOME_Magnifier_ZoomRegion_setROI (zoom_region,
00282 &roi,
00283 &ev);
00284 } else fprintf (stderr, "nil region!\n");
00285 }
00286 }
00287 }
00288 return TRUE;
00289 }
00290
00291 return FALSE;
00292 }
00293
00294 static int
00295 magnifier_main_refresh_all (gpointer data)
00296 {
00297 int i;
00298 Magnifier *magnifier = data;
00299 CORBA_any *dirty_bounds_any;
00300 CORBA_Environment ev;
00301 Bonobo_PropertyBag properties;
00302 GNOME_Magnifier_RectBounds *dirty_bounds;
00303 GNOME_Magnifier_ZoomRegionList *regions;
00304
00305 CORBA_exception_init (&ev);
00306
00307 if (!IS_MAGNIFIER (magnifier))
00308 return FALSE;
00309
00310 regions = GNOME_Magnifier_Magnifier_getZoomRegions (
00311 BONOBO_OBJREF (magnifier),
00312 &ev);
00313
00314 #ifdef DEBUG_REFRESH
00315 fprintf (stderr, "refreshing %d regions\n", regions->_length);
00316 #endif
00317
00318 properties = GNOME_Magnifier_Magnifier_getProperties (BONOBO_OBJREF (magnifier), &ev);
00319
00320 dirty_bounds_any = Bonobo_PropertyBag_getValue (properties, "source-display-bounds", &ev);
00321 if (BONOBO_EX (&ev)) {
00322 g_warning ("Error getting source-display-bounds");
00323 bonobo_main_quit ();
00324 return FALSE;
00325 }
00326
00327 dirty_bounds = (GNOME_Magnifier_RectBounds *) dirty_bounds_any->_value;
00328
00329 fprintf (stderr, "region to update: %d %d %d %d\n",
00330 dirty_bounds->x1, dirty_bounds->y1, dirty_bounds->x2, dirty_bounds->y2);
00331
00332 for (i = 0; i < regions->_length; ++i)
00333 GNOME_Magnifier_ZoomRegion_markDirty (
00334 regions->_buffer [i], dirty_bounds, &ev);
00335
00336 bonobo_object_release_unref (properties, NULL);
00337
00338 return TRUE;
00339 }
00340
00341 int
00342 main (int argc, char** argv)
00343 {
00344 GOptionContext *context;
00345 GNOME_Magnifier_RectBounds *roi = GNOME_Magnifier_RectBounds__alloc();
00346 GNOME_Magnifier_RectBounds *viewport = GNOME_Magnifier_RectBounds__alloc();
00347 CORBA_any *viewport_any;
00348 int x = 0, y = 0, fullwidth, fullheight;
00349 guint pan_handle = 0, refresh_handle = 0;
00350 CORBA_Environment ev;
00351 Bonobo_PropertyBag properties;
00352
00353 Magnifier *magnifier;
00354
00355 if (!bonobo_init (&argc, argv)) {
00356 g_error ("Could not initialize Bonobo");
00357 }
00358 CORBA_exception_init (&ev);
00359
00360 context = g_option_context_new ("- screen magnifier");
00361 g_option_context_add_main_entries (context, magnifier_options, "main options");
00362 g_option_context_set_ignore_unknown_options (context, TRUE);
00363 g_option_context_parse(context, &argc, &argv, NULL);
00364 g_option_context_free(context);
00365
00371 if (global_options.target_display) {
00372 gchar *string;
00373 string = g_strconcat ("DISPLAY=", global_options.target_display, NULL);
00374 putenv (string);
00375 } else {
00376 global_options.target_display = getenv ("DISPLAY");
00377 if (!global_options.target_display) {
00378 fprintf (stderr, _("Can't open display, DISPLAY is not set"));
00379 exit (1);
00380 }
00381 }
00382
00383 if (!global_options.source_display) {
00384 global_options.source_display = global_options.target_display;
00385 }
00386
00387 if (global_options.timing_pan_rate && global_options.timing_iterations == 0)
00388 {
00389 g_error ("Must specify timing_iterations when running pan test");
00390 }
00391
00392
00393 gtk_init (&argc, &argv);
00394
00395 if (global_options.ignore_damage)
00396 {
00397 g_setenv ("MAGNIFIER_IGNORE_DAMAGE", "1", TRUE);
00398 }
00399
00400 magnifier = magnifier_new (global_options.is_override_redirect);
00401
00402 properties = GNOME_Magnifier_Magnifier_getProperties (
00403 BONOBO_OBJREF (magnifier), &ev);
00404 if (ev._major != CORBA_NO_EXCEPTION) fprintf (stderr, "EXCEPTION\n");
00405
00406 if (global_options.source_display)
00407 bonobo_pbclient_set_string (properties, "source-display-screen",
00408 global_options.source_display, NULL);
00409
00410 if (global_options.target_display)
00411 bonobo_pbclient_set_string (properties, "target-display-screen",
00412 global_options.target_display, NULL);
00413
00414 if (global_options.cursor_set)
00415 bonobo_pbclient_set_string (properties, "cursor-set",
00416 global_options.cursor_set, NULL);
00417
00418 if (global_options.cursor_size)
00419 bonobo_pbclient_set_long (properties, "cursor-size",
00420 global_options.cursor_size, NULL);
00421
00422 else if (global_options.cursor_scale_factor != 0.0F)
00423 bonobo_pbclient_set_float (properties, "cursor-scale-factor",
00424 global_options.cursor_scale_factor, NULL);
00425 else
00426 bonobo_pbclient_set_float (properties, "cursor-scale-factor",
00427 global_options.zoom_factor, NULL);
00428
00429 if (global_options.cursor_color)
00430 bonobo_pbclient_set_ulong (properties, "cursor-color",
00431 global_options.cursor_color,
00432 NULL);
00433
00434 fullwidth = screen_width = gdk_screen_get_width (
00435 gdk_display_get_screen (magnifier->target_display,
00436 magnifier->target_screen_num));
00437 fullheight = screen_height = gdk_screen_get_height (
00438 gdk_display_get_screen (magnifier->target_display,
00439 magnifier->target_screen_num));
00440
00441 if (global_options.vertical_split) {
00442 screen_width /= 2;
00443 x = screen_width;
00444 }
00445 if (global_options.horizontal_split) {
00446 screen_height /= 2;
00447 }
00448
00449 fprintf (stderr, "initial viewport %d %d\n", (int) screen_width,
00450 (int) screen_height);
00451
00452 init_rect_bounds (viewport, x, y, x + screen_width, y + screen_height);
00453 viewport_any = bonobo_arg_new_from (TC_GNOME_Magnifier_RectBounds, viewport);
00454
00455 bonobo_pbclient_set_value (properties, "target-display-bounds",
00456 viewport_any,
00457 &ev);
00458 bonobo_arg_release (viewport_any);
00459
00460 if (global_options.vertical_split || global_options.horizontal_split)
00461 {
00462 init_rect_bounds (viewport, 0, 0, fullwidth-x, fullheight-y);
00463 viewport_any = bonobo_arg_new_from (TC_GNOME_Magnifier_RectBounds, viewport);
00464 bonobo_pbclient_set_value (properties, "source-display-bounds",
00465 viewport_any,
00466 &ev);
00467
00468 bonobo_arg_release (viewport_any);
00469 }
00470
00471 bonobo_object_release_unref (properties, NULL);
00472 properties = NULL;
00473
00474 if (global_options.vertical_split ||
00475 global_options.horizontal_split ||
00476 global_options.fullscreen)
00477 {
00478 int scroll_policy;
00479
00480 init_rect_bounds (roi, 0, 0, 100, 100);
00481 init_rect_bounds (viewport, 0, 0, screen_width, screen_height);
00482 zoom_region =
00483 GNOME_Magnifier_Magnifier_createZoomRegion (
00484 BONOBO_OBJREF (magnifier),
00485 global_options.zoom_factor,
00486 global_options.zoom_factor,
00487 roi,
00488 viewport,
00489 &ev);
00490
00491 properties = GNOME_Magnifier_ZoomRegion_getProperties (zoom_region, &ev);
00492 if (BONOBO_EX (&ev))
00493 fprintf (stderr, "EXCEPTION\n");
00494
00495 scroll_policy = global_options.smooth_scroll ?
00496 GNOME_Magnifier_ZoomRegion_SCROLL_SMOOTHEST :
00497 GNOME_Magnifier_ZoomRegion_SCROLL_FASTEST;
00498
00499 bonobo_pbclient_set_long (properties, "timing-iterations",
00500 global_options.timing_iterations, &ev);
00501 bonobo_pbclient_set_boolean (properties, "timing-output",
00502 global_options.timing_output, &ev);
00503 bonobo_pbclient_set_long (properties, "timing-pan-rate",
00504 global_options.timing_pan_rate, &ev);
00505 bonobo_pbclient_set_long (properties, "border-size",
00506 global_options.border_width, &ev);
00507 bonobo_pbclient_set_long (properties, "border-color",
00508 global_options.border_color, &ev);
00509 bonobo_pbclient_set_short (properties, "smooth-scroll-policy",
00510 (short) scroll_policy, &ev);
00511 bonobo_pbclient_set_boolean (properties, "use-test-pattern",
00512 global_options.test_pattern, &ev);
00513
00514 if (strcmp (global_options.smoothing_type, "none"))
00515 bonobo_pbclient_set_string (properties, "smoothing-type",
00516 global_options.smoothing_type, &ev);
00517
00518 if (global_options.invert_image)
00519 bonobo_pbclient_set_boolean (properties, "inverse-video",
00520 global_options.invert_image, NULL);
00521
00522 GNOME_Magnifier_Magnifier_addZoomRegion (
00523 BONOBO_OBJREF (magnifier),
00524 zoom_region,
00525 &ev);
00526
00527 bonobo_object_release_unref (properties, &ev);
00528 properties = NULL;
00529 }
00530
00531 if (global_options.timing_pan_rate)
00532 {
00533 GNOME_Magnifier_ZoomRegionList *zoom_regions;
00534 GNOME_Magnifier_RectBounds roi;
00535 roi.x1 = 100;
00536 roi.x2 = 100 + (screen_width / global_options.zoom_factor);
00537 roi.y1 = 0;
00538 roi.y2 = screen_height / global_options.zoom_factor;
00539
00540 zoom_regions = GNOME_Magnifier_Magnifier_getZoomRegions (
00541 BONOBO_OBJREF (magnifier), &ev);
00542
00543 if (zoom_regions && (zoom_regions->_length > 0))
00544 {
00545 GNOME_Magnifier_ZoomRegion_setROI (
00546 zoom_regions->_buffer[0], &roi, &ev);
00547 }
00548 }
00549 else if (global_options.timing_iterations)
00550 {
00551 refresh_handle = g_timeout_add (global_options.refresh_time,
00552 magnifier_main_test_image,
00553 magnifier);
00554 }
00555 else
00556 {
00557 if (global_options.ignore_damage ||
00558 !magnifier_source_has_damage_extension (magnifier))
00559 {
00560 refresh_handle = g_timeout_add (
00561 global_options.refresh_time,
00562 magnifier_main_refresh_all, magnifier);
00563 }
00564
00565 pan_handle = g_timeout_add (
00566 global_options.mouse_poll_time,
00567 magnifier_main_pan_image, magnifier);
00568 }
00569
00570 bonobo_main ();
00571
00572 if (refresh_handle)
00573 g_source_remove (refresh_handle);
00574
00575 if (pan_handle)
00576 g_source_remove (pan_handle);
00577
00578 return 0;
00579 }