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