2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2001 Sun Microsystems Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 #include <gdk/gdkwindow.h>
25 #include <libbonobo.h>
26 #include "magnifier.h"
27 #include "mag_image.h"
29 #define ENV_STRING_MAX_SIZE 128
32 * Our parent GObject type
34 #define PARENT_TYPE BONOBO_OBJECT_TYPE
36 struct sockaddr_un mag_server = { AF_UNIX , "/tmp/magnifier_socket" };
39 gchar *target_display;
40 gchar *source_display;
50 int fast_cmap_convert;
51 int no_initial_region;
54 static MagnifierOptions global_options = { ":0.0",
69 struct poptOption magnifier_options [] = {
70 {"target_display", 't', POPT_ARG_STRING, &global_options.target_display, 't', "specify display on which to show magnified view", NULL},
71 {"source_display", 's', POPT_ARG_STRING, &global_options.source_display, 's', "specify display to magnify", NULL},
72 {"vertical", 'v', POPT_ARG_NONE, &global_options.vertical_split, 'v', "split screen vertically (if target display = source display)", NULL},
73 {"horizontal", 'h', POPT_ARG_NONE, &global_options.horizontal_split, 'h', "split screen horizontally (if target display = source display)", NULL},
74 {"dual-head", 'd', POPT_ARG_NONE, &global_options.dual_head, 'd', "dual-head display mode (maps magnifier to second display)", NULL},
75 {"mouse follow", 'm', POPT_ARG_NONE, &global_options.mouse_follow, 'm', "track mouse movements", NULL},
76 {"refresh time", 'r', POPT_ARG_NONE, &global_options.min_refresh_time, 'r', "minimum refresh time for mouse follow and idle, in ms", NULL},
77 {"zoom (scale) factor", 'z', POPT_ARG_FLOAT, &global_options.zoom_factor, 'z', "zoom (scale) factor used to magnify source display", NULL},
78 /* {"invert image", 'i', POPT_ARG_NONE, &global_options.invert_image, 'i', "invert the image colormap", NULL}, */
79 {"fast-colormap-conversion", 'c', POPT_ARG_NONE, &global_options.fast_cmap_convert, 'c', "use faster colormap conversion algorithm (fails for 6 bit color)", NULL},
80 {"no-bonobo", '\0', POPT_ARG_NONE, &global_options.no_bonobo, '\0', "don't use bonobo for controls, use sockets", NULL},
81 {"no-initial-region", '\0', POPT_ARG_NONE, &global_options.no_initial_region, '\0', "don't create an initial zoom region", NULL},
82 {NULL, 0, 0, NULL, 0, 0}
87 static GtkWidget *window; /* TODO: clean up, with accessor func? */
90 magnifier_realize (GtkWidget *widget)
93 Atom wm_window_protocols[2];
94 static gboolean initialized = FALSE;
98 wm_window_protocols[0] = gdk_x11_get_xatom_by_name ("WM_DELETE_WINDOW");
99 wm_window_protocols[1] = gdk_x11_get_xatom_by_name ("_NET_WM_PING");
102 wm_hints.flags = InputHint;
103 wm_hints.input = False;
105 XSetWMHints (GDK_WINDOW_XDISPLAY (widget->window),
106 GDK_WINDOW_XWINDOW (widget->window), &wm_hints);
108 XSetWMProtocols (GDK_WINDOW_XDISPLAY (widget->window),
109 GDK_WINDOW_XWINDOW (widget->window), wm_window_protocols, 2);
118 static gboolean get_commands(GIOChannel* client,
119 GIOCondition condition,
124 memset(msg,0,MSG_LEN);
126 if((desc_client = accept(desc,(struct sockaddr*)&client_sockaddr,&size_client)) == -1){
127 perror("Could connect to client");exit(1);
130 read(desc_client,msg,sizeof(msg));
131 parse_message(msg, data);
137 magnifier_pack_regions (Magnifier *magnifier)
140 * this call prevents resizing, which is a bother, but required to
141 * work around dtwm incompatibilities. Perhaps a better workaround will
142 * be found, or we can make this a runtime option.
144 gtk_widget_set_size_request (magnifier->mag_data->output_window,
145 magnifier->mag_data->mag_width,
146 magnifier->mag_data->mag_height);
148 gdk_window_move(magnifier->mag_data->output_window->window,
149 magnifier->mag_data->mag_x,
150 magnifier->mag_data->mag_y);
154 int main (int argc, char** argv){
155 GIOChannel *mag_channel;
157 char env_string[ENV_STRING_MAX_SIZE];
159 /* TODO: finish replacing socket connection IPC with bonobo service. */
160 Magnifier *magnifier;
162 GdkGeometry geometry;
166 size_client = sizeof(client_sockaddr);
170 if (!bonobo_init (&argc, argv))
172 g_error ("Could not initialize Bonobo");
175 magnifier = magnifier_new (argc, argv);
177 magnifier->mag_data->follow_mouse =
178 global_options.mouse_follow;
179 magnifier->mag_data->color_inverted =
180 global_options.invert_image;
181 if (!global_options.no_initial_region)
183 magnifier->mag_data->zoom_regions =
184 g_list_prepend (magnifier->mag_data->zoom_regions,
185 g_new0 (ZoomRegionData, 1));
186 magnifier->mag_data->factor_x = (int) global_options.zoom_factor;
187 magnifier->mag_data->factor_y = (int) global_options.zoom_factor;
190 g_print ("starting magnifier with no initial zoom region\n");
191 magnifier->mag_data->mag_width = 0;
192 magnifier->mag_data->mag_height = 0;
194 /* TODO: enable fractional magnifications option? */
195 if (global_options.target_display) {
196 g_snprintf (env_string, (size_t) (ENV_STRING_MAX_SIZE-1), "DISPLAY=%s", global_options.target_display);
199 gtk_init (&argc, &argv);
201 window = g_object_connect (gtk_widget_new (gtk_window_get_type (),
204 "type", GTK_WINDOW_TOPLEVEL,
205 "title", "magnifier",
207 "allow_shrink", FALSE,
210 "signal::realize", magnifier_realize, NULL,
211 "signal::destroy", magnifier_exit, NULL,
214 drawing_area = gtk_drawing_area_new();
215 gtk_container_add (GTK_CONTAINER (window),drawing_area);
216 gtk_widget_add_events(GTK_WIDGET(drawing_area),GDK_BUTTON_PRESS_MASK);
217 gtk_signal_connect (GTK_OBJECT (drawing_area),"expose_event",
218 GTK_SIGNAL_FUNC(expose_event),NULL);
221 if (global_options.no_bonobo) {
222 if((desc = socket(AF_UNIX,SOCK_STREAM,0)) == -1){
223 perror("Socket");exit(1);
225 unlink("/tmp/magnifier_socket");
227 if(bind(desc,(struct sockaddr*)&mag_server,sizeof(mag_server)) == -1){
228 perror("Bind");exit(1);
231 if(listen(desc,100) == -1){
232 perror("Listen");exit(1);
234 mag_channel = g_io_channel_unix_new(desc);
235 g_io_add_watch(mag_channel,
238 magnifier->mag_data);
242 /* init image information */
243 if (!global_options.source_display) global_options.source_display = gdk_get_display();
244 dpyname = global_options.source_display + (strlen(global_options.source_display) - 1);
245 screen_num = atoi(dpyname);
246 if (!global_options.target_display) {
247 if((screen_num == 0) && global_options.dual_head)
249 else if (global_options.dual_head)
251 global_options.target_display =
252 (char *) malloc (strlen (global_options.source_display));
253 strncpy (global_options.target_display,
254 global_options.source_display,
255 strlen(global_options.source_display)-2);
256 global_options.target_display[strlen(global_options.source_display)-2] = 0;
257 sprintf(global_options.target_display, "%s.%d",
258 global_options.target_display, screen_num);
261 printf("displays: source=%s; target=%s\n",
262 global_options.source_display,
263 global_options.target_display);
265 magnifier->mag_data->source_display = XOpenDisplay (global_options.source_display);
266 magnifier->mag_data->target_display = GDK_DISPLAY();
268 spi_image_root_window = RootWindow(magnifier->mag_data->source_display, screen_num);
269 gdk_pixbuf_xlib_init (magnifier->mag_data->source_display, screen_num);
270 image = gdk_pixbuf_new (GDK_COLORSPACE_RGB,FALSE, 8,
271 DisplayWidth (magnifier->mag_data->source_display,screen_num)/2,
272 DisplayHeight(magnifier->mag_data->source_display,screen_num)/2);
273 scaled_image = gdk_pixbuf_new (GDK_COLORSPACE_RGB,FALSE, 8,
274 DisplayWidth (magnifier->mag_data->target_display,screen_num),
275 DisplayHeight(magnifier->mag_data->target_display,screen_num));
276 if (global_options.vertical_split)
278 magnifier->mag_data->mag_width =
279 DisplayWidth (magnifier->mag_data->target_display,screen_num)/2;
280 magnifier->mag_data->mag_height =
281 DisplayHeight (magnifier->mag_data->target_display, screen_num);
283 else if (global_options.horizontal_split)
285 magnifier->mag_data->mag_width =
286 DisplayWidth (magnifier->mag_data->target_display, screen_num);
287 magnifier->mag_data->mag_height =
288 DisplayHeight (magnifier->mag_data->target_display,screen_num)/2;
290 else if (global_options.fullscreen)
292 magnifier->mag_data->mag_width =
293 DisplayWidth (magnifier->mag_data->target_display, screen_num);
294 magnifier->mag_data->mag_height =
295 DisplayHeight (magnifier->mag_data->target_display,screen_num);
297 magnifier->mag_data->mag_x =
298 DisplayWidth (magnifier->mag_data->target_display, screen_num)
299 - magnifier->mag_data->mag_width;
300 magnifier->mag_data->mag_y =
301 DisplayHeight (magnifier->mag_data->target_display, screen_num)
302 - magnifier->mag_data->mag_height;
304 magnifier->mag_data->output_window = window;
305 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
306 gtk_widget_show_all (window);
308 magnifier_pack_regions (magnifier);
310 /* if (global_options.fullscreen) */
311 gdk_window_stick (window->window);
312 gdk_window_set_functions(window->window, 0);
313 gdk_window_raise(window->window);
315 gtk_timeout_add(global_options.min_refresh_time, display_image, magnifier->mag_data);
317 obj_id = "OAFIID:Accessibility_Util_Magnifier:proto0.1";
319 if (! global_options.no_bonobo)
321 int ret = bonobo_activation_active_server_register (
322 obj_id, BONOBO_OBJREF (magnifier));
324 if (ret == Bonobo_ACTIVATION_REG_SUCCESS)
334 unlink("magnifier_socket");
339 impl_magnifier_fullscreen (PortableServer_Servant servant,
340 CORBA_Environment *ev)
342 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
343 magnifier->mag_data->mag_width = DisplayWidth (magnifier->mag_data->target_display, screen_num);
344 magnifier->mag_data->mag_height = DisplayHeight (magnifier->mag_data->target_display, screen_num);
348 impl_magnifier_set_extents (PortableServer_Servant servant,
353 CORBA_Environment *ev)
355 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
356 magnifier->mag_data->mag_width = x2 - x1;
357 magnifier->mag_data->mag_height = y2 - y1;
358 gdk_window_move(window->window, x1, y1);
362 impl_magnifier_set_follow_mouse (PortableServer_Servant servant,
363 const CORBA_boolean follow_mouse,
364 CORBA_Environment *ev)
366 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
367 magnifier->mag_data->follow_mouse = (int) follow_mouse;
371 impl_magnifier_set_contrast (PortableServer_Servant servant,
372 const CORBA_short contrast,
373 CORBA_Environment *ev)
375 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
376 magnifier->mag_data->contrast = (int) contrast;
380 impl_magnifier_set_source_display (PortableServer_Servant servant,
381 const CORBA_char *display,
382 CORBA_Environment *ev)
384 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
385 magnifier->mag_data->source_display =
386 XOpenDisplay (global_options.source_display);
390 impl_magnifier_set_target_display (PortableServer_Servant servant,
391 const CORBA_char *display,
392 CORBA_Environment *ev)
394 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
395 magnifier->mag_data->target_display = GDK_DISPLAY();
399 impl_magnifier_goto (PortableServer_Servant servant,
402 CORBA_Environment *ev)
404 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
405 magnifier->mag_data->center.x = (int) x;
406 magnifier->mag_data->center.y = (int) y;
410 impl_magnifier_set_roi (PortableServer_Servant servant,
411 const CORBA_short zoom_region,
416 CORBA_Environment *ev)
418 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
419 magnifier->mag_data->center.x = (int) ((x1 + x2)/2);
420 magnifier->mag_data->center.y = (int) ((y1 + y2)/2);
424 impl_magnifier_set_mag_factor (PortableServer_Servant servant,
425 const CORBA_short zoom_region,
426 const CORBA_float mag_factor_x,
427 const CORBA_float mag_factor_y,
428 CORBA_Environment *ev)
430 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
431 if (zoom_region == (CORBA_short) 0) /* TODO: fix for multi-zoom-regions */
433 magnifier->mag_data->factor_x = (float) mag_factor_x;
434 magnifier->mag_data->factor_y = (float) mag_factor_y;
439 impl_magnifier_mark_dirty (PortableServer_Servant servant,
440 const CORBA_short zoom_region,
445 CORBA_Environment *ev)
447 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
448 /* TODO: implement */
452 impl_magnifier_mark_unmanaged (PortableServer_Servant servant,
453 const CORBA_short zoom_region,
454 CORBA_Environment *ev)
456 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
457 /* TODO: implement */
461 impl_magnifier_create_zoom_region (PortableServer_Servant servant,
462 const CORBA_float zx,
463 const CORBA_float zy,
468 CORBA_Environment *ev)
470 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
471 if (magnifier->mag_data->zoom_regions == NULL)
473 magnifier->mag_data->zoom_regions =
474 g_list_prepend (magnifier->mag_data->zoom_regions,
475 g_new0 (ZoomRegionData, 1));
476 magnifier->mag_data->factor_x = (int) zx;
477 magnifier->mag_data->factor_y = (int) zy;
478 magnifier->mag_data->mag_x = x1;
479 magnifier->mag_data->mag_y = y1;
480 magnifier->mag_data->mag_width = (x2 - x1);
481 magnifier->mag_data->mag_height = (y2 - y1);
482 magnifier_pack_regions (magnifier);
492 impl_magnifier_get_zoom_region_params (PortableServer_Servant servant,
493 const CORBA_short zoom_region,
495 CORBA_float * zy, CORBA_long * x1,
496 CORBA_long * y1, CORBA_long * x2,
498 CORBA_Environment * ev)
500 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
501 if (zoom_region == (CORBA_short) 0)
503 *zx = magnifier->mag_data->factor_x;
504 *zy = magnifier->mag_data->factor_y;
507 *x2 = *x1 + magnifier->mag_data->mag_width;
508 *y2 = *y1 + magnifier->mag_data->mag_height;
511 else return CORBA_FALSE;
515 impl_magnifier_resize_zoom_region (PortableServer_Servant servant,
516 const CORBA_short zoom_region,
517 const CORBA_long x1, const CORBA_long y1,
518 const CORBA_long x2, const CORBA_long y2,
519 CORBA_Environment * ev)
521 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
522 if (zoom_region == 0)
524 magnifier->mag_data->mag_x = x1;
525 magnifier->mag_data->mag_y = y1;
526 magnifier->mag_data->mag_width = (x2 - x1);
527 magnifier->mag_data->mag_height = (y2 - y1);
528 magnifier_pack_regions (magnifier);
533 impl_magnifier_destroy_zoom_region (PortableServer_Servant servant,
534 const CORBA_short zoom_region,
535 CORBA_Environment * ev)
537 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
538 if (zoom_region == 0)
540 g_list_free (magnifier->mag_data->zoom_regions);
545 impl_magnifier_clear_all_zoom_regions (PortableServer_Servant servant,
546 CORBA_Environment * ev)
548 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
549 g_list_free (magnifier->mag_data->zoom_regions);
550 magnifier->mag_data->zoom_regions = NULL;
554 impl_magnifier_exit (PortableServer_Servant servant, CORBA_Environment *ev)
556 Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
557 if (magnifier->mag_data->zoom_regions)
558 g_list_free (magnifier->mag_data->zoom_regions);
559 g_free (magnifier->mag_data);
564 magnifier_class_init (MagnifierClass *klass)
566 GObjectClass * object_class = (GObjectClass *) klass;
567 POA_Accessibility_Magnifier__epv *epv = &klass->epv;
569 object_class->finalize = magnifier_finalize;
571 epv->_set_SourceDisplay = impl_magnifier_set_source_display;
572 epv->_set_TargetDisplay = impl_magnifier_set_target_display;
573 epv->setROI = impl_magnifier_set_roi;
574 epv->setMagFactor = impl_magnifier_set_mag_factor;
575 epv->markDirty = impl_magnifier_mark_dirty;
576 epv->markUnmanaged = impl_magnifier_mark_unmanaged;
577 epv->createZoomRegion = impl_magnifier_create_zoom_region;
578 epv->getZoomRegionParams = impl_magnifier_get_zoom_region_params;
579 epv->resizeZoomRegion = impl_magnifier_resize_zoom_region;
580 epv->destroyZoomRegion = impl_magnifier_destroy_zoom_region;
581 epv->clearAllZoomRegions = impl_magnifier_clear_all_zoom_regions;
582 epv->exit = impl_magnifier_exit;
586 magnifier_init (Magnifier *magnifier)
588 magnifier->mag_data = (MagnifierData *) g_new0 (MagnifierData, 1);
589 magnifier->mag_data->factor_x = 2;
590 magnifier->mag_data->factor_y = 2;
591 magnifier->mag_data->contrast = 0;
592 magnifier->mag_data->color_inverted = FALSE;
593 magnifier->mag_data->fast_rgb_convert = FALSE;
594 magnifier->mag_data->center.x = 0;
595 magnifier->mag_data->center.y = 0;
596 magnifier->mag_data->zoom_regions = NULL;
600 magnifier_get_type (void)
602 static GType type = 0;
605 static const GTypeInfo tinfo = {
606 sizeof (MagnifierClass),
607 (GBaseInitFunc) NULL,
608 (GBaseFinalizeFunc) NULL,
609 (GClassInitFunc) magnifier_class_init,
610 (GClassFinalizeFunc) NULL,
611 NULL, /* class data */
614 (GInstanceInitFunc) magnifier_init,
615 NULL /* value table */
618 * Here we use bonobo_type_unique instead of
619 * gtk_type_unique, this auto-generates a load of
620 * CORBA structures for us. All derived types must
621 * use bonobo_type_unique.
623 type = bonobo_type_unique (
625 POA_Accessibility_Magnifier__init,
627 G_STRUCT_OFFSET (MagnifierClass, epv),
636 magnifier_new (int argc, char **argv)
639 Magnifier *magnifier =
640 MAGNIFIER (g_object_new (magnifier_get_type(), NULL));
641 ctx = poptGetContext ("magnifier",
647 while (poptGetNextOpt (ctx) >= 0)