Added directory 'util' for accessibility-related
[platform/core/uifw/at-spi2-atk.git] / util / magnifier.c
1 #include <popt.h>
2 #include <gdk/gdkwindow.h>
3 #include <bonobo/Bonobo.h>
4 #include "magnifier.h"
5 #include "mag_image.h"
6
7 #define ENV_STRING_MAX_SIZE 128
8
9 /*
10  * Our parent GObject type
11  */
12 #define PARENT_TYPE BONOBO_OBJECT_TYPE
13
14 struct sockaddr_un mag_server = { AF_UNIX ,  "/tmp/magnifier_socket" };
15
16 typedef struct {
17         gchar *target_display;
18         gchar *source_display;
19         int   vertical_split;
20         int   horizontal_split;
21         int   dual_head;
22         int   fullscreen;
23         int   mouse_follow;
24         int   invert_image;
25         float zoom_factor;
26         int   refresh_time;
27         int   no_bonobo;
28 } MagnifierOptions;
29
30 static MagnifierOptions global_options = { ":0.0",
31                                            ":0.0",
32                                            0,
33                                            0,
34                                            0,
35                                            0,
36                                            0,
37                                            0,
38                                            2.0,
39                                            200,
40                                            0
41                                          };
42
43 struct poptOption magnifier_options [] = {
44         {"target_display", 't', POPT_ARG_STRING, &global_options.target_display, 't', "specify display on which to show magnified view", NULL},
45         {"source_display", 's', POPT_ARG_STRING, &global_options.source_display, 's', "specify display to magnify", NULL},
46         {"vertical", 'v', POPT_ARG_NONE, &global_options.vertical_split, 'v', "split screen vertically (if target display = source display)", NULL},
47         {"horizontal", 'h', POPT_ARG_NONE, &global_options.horizontal_split, 'h', "split screen horizontally (if target display = source display)", NULL},
48         {"dual-head", 'd', POPT_ARG_NONE, &global_options.dual_head, 'd', "dual-head display mode (maps magnifier to second display)", NULL},
49         {"mouse follow", 'm', POPT_ARG_NONE, &global_options.mouse_follow, 'm', "track mouse movements", NULL},
50         {"refresh time", 'r', POPT_ARG_NONE, &global_options.refresh_time, 'r', "refresh time for mouse follow and idle, in ms", NULL},
51         {"zoom (scale) factor", 'z', POPT_ARG_FLOAT, &global_options.zoom_factor, 'z', "zoom (scale) factor used to magnify source display", NULL}, 
52 /*      {"invert image", 'i', POPT_ARG_NONE, &global_options.invert_image, 'i', "invert the image colormap", NULL}, */
53         {"no-bonobo", '\0', POPT_ARG_NONE, &global_options.no_bonobo, '\0', "don't use bonobo for controls, use sockets", NULL},
54         {NULL, 0, 0, NULL, 0, 0}
55 };
56
57 #define MSG_LEN 80
58
59 static gboolean get_commands(GIOChannel* client,
60                              GIOCondition condition,
61                              gpointer data){
62   char msg[MSG_LEN];
63   int desc_client = 0;
64   
65   memset(msg,0,MSG_LEN);
66   
67   if((desc_client = accept(desc,(struct sockaddr*)&client_sockaddr,&size_client)) == -1){
68     perror("Could connect to client");exit(1);
69   }
70   
71   read(desc_client,msg,sizeof(msg));
72   parse_message(msg, data);
73   return TRUE;
74
75 }
76
77 int main (int argc, char** argv){
78   GtkWidget *window;
79   GIOChannel *mag_channel;
80   char *dpyname;
81   char env_string[ENV_STRING_MAX_SIZE];
82
83   /* TODO: finish replacing socket connection IPC with bonobo service. */
84   Magnifier *magnifier;
85   char * obj_id;
86   
87   x_cmap = NULL;
88
89   size_client = sizeof(client_sockaddr);
90
91   image = NULL;
92
93   if (!bonobo_init (&argc, argv))
94     {
95       g_error ("Could not initialize Bonobo");
96     }
97
98   magnifier = magnifier_new (argc, argv);
99   
100   magnifier->mag_data->follow_mouse =
101           global_options.mouse_follow;
102   magnifier->mag_data->color_inverted =
103           global_options.invert_image;
104   magnifier->mag_data->factor =
105     (int) global_options.zoom_factor; 
106
107   /* TODO: enable fractional magnifications ? */
108   
109   if (global_options.target_display) {
110     snprintf (env_string, (size_t) (ENV_STRING_MAX_SIZE-1), "DISPLAY=%s", global_options.target_display);
111     putenv (env_string);
112   }
113   gtk_init (&argc, &argv);
114
115   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
116   drawing_area = gtk_drawing_area_new();
117   gtk_container_add (GTK_CONTAINER (window),drawing_area);
118   gtk_widget_add_events(GTK_WIDGET(drawing_area),GDK_BUTTON_PRESS_MASK);
119   gtk_signal_connect (GTK_OBJECT (drawing_area),"expose_event",
120                       GTK_SIGNAL_FUNC(expose_event),NULL);
121   
122   /* Init socket */
123   if (global_options.no_bonobo) {
124     if((desc = socket(AF_UNIX,SOCK_STREAM,0)) == -1){
125       perror("Socket");exit(1);
126     }
127     unlink("/tmp/magnifier_socket");
128
129     if(bind(desc,(struct sockaddr*)&mag_server,sizeof(mag_server)) == -1){
130        perror("Bind");exit(1);
131     }
132
133     if(listen(desc,100) == -1){
134        perror("Listen");exit(1);
135     }
136     mag_channel = g_io_channel_unix_new(desc);
137     g_io_add_watch(mag_channel,
138                    G_IO_IN | G_IO_ERR,
139                    get_commands,
140                    magnifier->mag_data);
141
142   }
143   
144   /* init image information */
145   if (!global_options.source_display) global_options.source_display = gdk_get_display();
146   dpyname = global_options.source_display + (strlen(global_options.source_display) - 1);
147   screen_num = atoi(dpyname);
148   if (!global_options.target_display) {
149     if((screen_num == 0) && global_options.dual_head)
150       screen_num++;
151     else if (global_options.dual_head)
152       screen_num--;
153     global_options.target_display =
154             (char *) malloc (strlen (global_options.source_display));
155     strncpy (global_options.target_display,
156              global_options.source_display,
157              strlen(global_options.source_display)-2);
158     global_options.target_display[strlen(global_options.source_display)-2] = 0;
159     sprintf(global_options.target_display, "%s.%d",
160             global_options.target_display, screen_num);
161   }
162
163   printf("displays: source=%s; target=%s\n",
164          global_options.source_display,
165          global_options.target_display);
166   
167   magnifier->mag_data->source_display = XOpenDisplay (global_options.source_display);
168   magnifier->mag_data->target_display = GDK_DISPLAY();
169
170   image_root_window = RootWindow(magnifier->mag_data->source_display, screen_num);
171   gdk_pixbuf_xlib_init (magnifier->mag_data->source_display, screen_num);
172   image = gdk_pixbuf_new        (GDK_COLORSPACE_RGB,FALSE, 8,
173                                 DisplayWidth (magnifier->mag_data->source_display,screen_num)/2,
174                                 DisplayHeight(magnifier->mag_data->source_display,screen_num)/2);
175   scaled_image = gdk_pixbuf_new (GDK_COLORSPACE_RGB,FALSE, 8,
176                                 DisplayWidth (magnifier->mag_data->target_display,screen_num),
177                                 DisplayHeight(magnifier->mag_data->target_display,screen_num));
178   if (global_options.vertical_split)
179           magnifier->mag_data->mag_width = DisplayWidth (magnifier->mag_data->target_display,screen_num)/2;
180   else
181           magnifier->mag_data->mag_width = DisplayWidth (magnifier->mag_data->target_display, screen_num);
182   if (global_options.horizontal_split)
183           magnifier->mag_data->mag_height = DisplayHeight (magnifier->mag_data->target_display,screen_num)/2;
184   else magnifier->mag_data->mag_height = DisplayHeight (magnifier->mag_data->target_display, screen_num);
185   gtk_widget_show_all (window);
186
187   gdk_window_move(window->window,
188                   gdk_screen_width() - magnifier->mag_data->mag_width,
189                   gdk_screen_height() - magnifier->mag_data->mag_height);
190   gdk_window_resize (window->window, magnifier->mag_data->mag_width, magnifier->mag_data->mag_height);
191   magnifier->mag_data->output_window = window;
192   if (global_options.fullscreen) gdk_window_stick (window->window);
193   gdk_window_set_decorations(window->window, 0);
194   gdk_window_set_functions(window->window, 0);
195   gdk_window_raise(window->window);
196   
197   gtk_timeout_add(global_options.refresh_time, display_image, magnifier->mag_data);
198
199   obj_id = "OAFIID:Accessibility_Util_Magnifier:proto0.1";
200
201   if (! global_options.no_bonobo)
202     {     
203       bonobo_activation_active_server_register (
204           obj_id,
205           bonobo_object_corba_objref (bonobo_object (magnifier)));
206
207       bonobo_main ();
208     }
209   else
210     {
211       gtk_main ();
212     }
213
214   unlink("magnifier_socket");
215   return 0;
216 }
217
218 static void
219 impl_magnifier_fullscreen (PortableServer_Servant servant,
220                            CORBA_Environment *ev)
221 {
222 }
223                                    
224 static void
225 impl_magnifier_set_extents (PortableServer_Servant servant,
226                             CORBA_long x1,
227                             CORBA_long y1,
228                             CORBA_long x2,
229                             CORBA_long y2,
230                             CORBA_Environment *ev)
231 {
232 }
233
234 static void
235 impl_magnifier_set_follow_mouse (PortableServer_Servant servant,
236                                  const CORBA_boolean follow_mouse,
237                                  CORBA_Environment *ev)
238 {
239   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
240   magnifier->mag_data->follow_mouse = (int) follow_mouse;
241 }
242
243 static void
244 impl_magnifier_set_contrast (PortableServer_Servant servant,
245                              const CORBA_short contrast,
246                              CORBA_Environment *ev)
247 {
248   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
249   magnifier->mag_data->contrast = (int) contrast;
250 }
251
252 static void
253 impl_magnifier_set_source_display (PortableServer_Servant servant,
254                                    const CORBA_char *display,
255                                    CORBA_Environment *ev)
256 {
257   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
258   magnifier->mag_data->source_display =
259           XOpenDisplay (global_options.source_display);
260 }
261
262 static void
263 impl_magnifier_set_target_display (PortableServer_Servant servant,
264                                    const CORBA_char *display,
265                                    CORBA_Environment *ev)
266 {
267   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
268   magnifier->mag_data->target_display = GDK_DISPLAY();
269 }
270
271 static void
272 impl_magnifier_goto (PortableServer_Servant servant,
273                      const CORBA_long x,
274                      const CORBA_long y,
275                      CORBA_Environment *ev)
276 {
277   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
278   magnifier->mag_data->center.x = (int) x;
279   magnifier->mag_data->center.y = (int) y;
280 }
281
282 static void
283 impl_magnifier_set_roi (PortableServer_Servant servant,
284                         const CORBA_long x1,
285                         const CORBA_long y1,
286                         const CORBA_long x2,
287                         const CORBA_long y2,
288                         CORBA_Environment *ev)
289 {
290   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
291   magnifier->mag_data->center.x = (int) ((x1 + x2)/2);
292   magnifier->mag_data->center.y = (int) ((y1 + y2)/2);
293 }
294
295 static void
296 impl_magnifier_set_mag_factor (PortableServer_Servant servant,
297                                const CORBA_float mag_factor,
298                                CORBA_Environment *ev)
299 {
300   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
301   magnifier->mag_data->factor = (float) mag_factor;
302 }
303
304 static void
305 impl_magnifier_exit (PortableServer_Servant servant, CORBA_Environment *ev)
306 {
307         ;
308 }
309
310 static void
311 magnifier_class_init (MagnifierClass *klass)
312 {
313         GObjectClass * object_class = (GObjectClass *) klass;
314         POA_Accessibility_Magnifier__epv *epv = &klass->epv;
315 /*
316         object_class->finalize = magnifier_finalize;
317 */
318         epv->_set_SourceDisplay = impl_magnifier_set_source_display;
319         epv->_set_TargetDisplay = impl_magnifier_set_target_display;
320         epv->setROI = impl_magnifier_set_roi;
321         epv->_set_MagFactor = impl_magnifier_set_mag_factor;
322         epv->exit = impl_magnifier_exit;
323 }
324
325 static void
326 magnifier_init (Magnifier *magnifier)
327 {
328   magnifier->mag_data = (MagnifierData *) g_new0 (MagnifierData, 1);
329   magnifier->mag_data->factor = 2;
330   magnifier->mag_data->contrast = 0;
331   magnifier->mag_data->color_inverted = FALSE;
332   magnifier->mag_data->center.x = 0;
333   magnifier->mag_data->center.y = 0;
334 }
335
336 GType
337 magnifier_get_type (void)
338 {
339         static GType type = 0;
340
341         if (!type) {
342                 static const GTypeInfo tinfo = {
343                         sizeof (MagnifierClass),
344                         (GBaseInitFunc) NULL,
345                         (GBaseFinalizeFunc) NULL,
346                         (GClassInitFunc) magnifier_class_init,
347                         (GClassFinalizeFunc) NULL,
348                         NULL, /* class data */
349                         sizeof (Magnifier),
350                         0, /* n preallocs */
351                         (GInstanceInitFunc) magnifier_init,
352                         NULL /* value table */
353                 };
354                 /*
355                  *   Here we use bonobo_type_unique instead of
356                  * gtk_type_unique, this auto-generates a load of
357                  * CORBA structures for us. All derived types must
358                  * use bonobo_type_unique.
359                  */
360                 type = bonobo_type_unique (
361                         PARENT_TYPE,
362                         POA_Accessibility_Magnifier__init,
363                         NULL,
364                         G_STRUCT_OFFSET (MagnifierClass, epv),
365                         &tinfo,
366                         "Magnifier");
367         }
368
369         return type;
370 }
371
372 Magnifier *
373 magnifier_new(int argc, char **argv)
374 {
375   poptContext ctx;      
376   Magnifier *magnifier =
377           MAGNIFIER (g_object_new (magnifier_get_type(), NULL));
378   ctx = poptGetContext ("magnifier",
379                         argc,
380                         (const char **)argv,
381                         magnifier_options,
382                         0);
383
384   while (poptGetNextOpt (ctx) >= 0)
385         /**/;
386
387   return magnifier;
388 }
389
390
391
392
393
394
395
396
397
398
399
400
401
402     
403
404
405