Added simple scanning to the virtual keyboard demo, to show one way to
authorbillh <billh@e2bd861d-eb25-0410-b326-f6ed22b6b98c>
Sun, 25 Nov 2001 14:47:03 +0000 (14:47 +0000)
committerbillh <billh@e2bd861d-eb25-0410-b326-f6ed22b6b98c>
Sun, 25 Nov 2001 14:47:03 +0000 (14:47 +0000)
do it with glib APIs.
Added an implementation of the Magnifier:getZoomRegionParams IDL to the
simple magnifier.

git-svn-id: http://svn.gnome.org/svn/at-spi/trunk@115 e2bd861d-eb25-0410-b326-f6ed22b6b98c

ChangeLog
at-bridge/bridge.c
atk-bridge/bridge.c
cspi/spi_registry.c
libspi/Makefile.am
libspi/deviceeventcontroller.c
registryd/deviceeventcontroller.c
test/keysynth-demo.c
util/mag_client.c
util/mag_image.h
util/magnifier.c

index 5a484a8..7605b67 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2001-11-25  Bill Haneman  <bill.haneman@sun.com>
+
+       * test/keysynth-demo.c:
+       Turned this into a simple scanning keyboard, to demonstrate the
+       use of g_timeout_add () as a means of creating timers for
+       scanning, and the use of GtkStyle for visually indicating when
+       virtual keyboard elements are selected.
+
+       keysynth-demo now listens to any keyboard keys with zero-valued
+       keycodes (i.e. 'unused' keys) and interprets them as
+       single-switches.
+
+       Reworked the shiftlatch code so that shift-down state isn't held
+       for long periods (it's only synthesized immediately prior to
+       the keysynth event it's modifying).  Note that shiftlatch in this
+       demo is a convenience, not intended to take the place of AccessX 
+       which is the better choice for getting 'sticky' modifier keys.
+
+       * libspi/deviceeventcontroller.c:
+       * at-bridge/bridge.c:
+       * cspi/spi_registry.c:
+       Removed some debug print stuff, and put other verbosity in #ifdef
+       blocks.
+
+       * util/magnifier.c:
+       * util/mag_image.h:
+       Implemented some more of the magnifier IDL for the simple
+       magnifier: namely, getZoomRegionParams. 
+       Added mag_x and mag_y members to MagnifierData struct, aid of this
+       implementation.
+       Added GtkWindow::realize signal handler to magnifier, to keep it
+       from receiving keyboard focus from the WM.
+
 2001-11-23  Mark McLoughlin  <mark@skynet.ie>
 
        * cspi/spi-private.h: my guess at what michael forgot
index 29fb569..fe5ff16 100644 (file)
@@ -31,7 +31,7 @@
 #include "accessible.h"
 #include "application.h"
 
-#define SPI_BRIDGE_DEBUG 1
+/* #define SPI_BRIDGE_DEBUG 1 */
 
 #define APP_STATIC_BUFF_SZ 64
 
@@ -279,8 +279,6 @@ bridge_state_event_listener (GSignalInvocationHint *signal_hint,
   return TRUE;
 }
 
-#define SPI_DEBUG
-
 static Accessibility_KeyStroke *
 accessibility_keystroke_from_atk_key_event (AtkKeyEventStruct *event)
 {
index 29fb569..fe5ff16 100644 (file)
@@ -31,7 +31,7 @@
 #include "accessible.h"
 #include "application.h"
 
-#define SPI_BRIDGE_DEBUG 1
+/* #define SPI_BRIDGE_DEBUG 1 */
 
 #define APP_STATIC_BUFF_SZ 64
 
@@ -279,8 +279,6 @@ bridge_state_event_listener (GSignalInvocationHint *signal_hint,
   return TRUE;
 }
 
-#define SPI_DEBUG
-
 static Accessibility_KeyStroke *
 accessibility_keystroke_from_atk_key_event (AtkKeyEventStruct *event)
 {
index dff0c63..cd6e7df 100644 (file)
@@ -284,6 +284,7 @@ registerAccessibleKeystrokeListener (AccessibleKeystrokeListener *listener,
           /* we overload the keyset long w/keycodes, the - bit acts as a flag */
           key_set->_buffer[i] = (keys->keysyms[i]) ? keys->keysyms[i] :
                                                 -keys->keycodes[i];
+         /* g_print ("key-set %d = %d\n", i, (int) key_set->_buffer[i]); */
         }
     }
   /* copy the event filter values from the C api into the CORBA KeyEventTypeSeq */
index d5c2c4f..977ace8 100644 (file)
@@ -6,7 +6,7 @@ INCLUDES = -I $(top_srcdir)           \
 
 LDFLAGS = $(LIBSPI_LIBS) $(XTST_LIBS) @LT_VERSION_INFO@
 
-DEBUG_CFLAGS=-DSPI_DEBUG
+#DEBUG_CFLAGS=-DSPI_DEBUG
 
 CFLAGS += $(DEBUG_CFLAGS)
 
index cc88dce..75ec325 100644 (file)
@@ -268,11 +268,18 @@ key_set_contains_key (Accessibility_KeySet *key_set, Accessibility_KeyStroke *ke
 
   for (i=0; i<len; ++i)
     {
-      g_print ("key_set[%d] = %d\n", i, (int) key_set->_buffer[i]);
-      if (key_set->_buffer[i] == (CORBA_long) key_event->keyID) return TRUE;       
+#ifdef SPI_KEYEVENT_DEBUG          
+      g_print ("key_set[%d] = %d; key_event %d, code %d\n",
+               i,
+              (int) key_set->_buffer[i],
+              (int) key_event->keyID,
+              (int) key_event->keycode); 
+#endif
+      if (key_set->_buffer[i] == (CORBA_long) key_event->keyID) return TRUE;
+      if (key_set->_buffer[i] == (CORBA_long) -key_event->keycode) return TRUE;
     }
   
-  return TRUE;
+  return FALSE;
 }
 
 static gboolean
@@ -294,7 +301,7 @@ key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq *type_seq,
 
   for (i=0; i<len; ++i)
     {
-      g_print ("type_seq[%d] = %d\n", i, (int) type_seq->_buffer[i]);
+/*      g_print ("type_seq[%d] = %d\n", i, (int) type_seq->_buffer[i]); */
       if (type_seq->_buffer[i] == (CORBA_long) key_event->type) return TRUE;       
     }
   
@@ -339,7 +346,13 @@ notify_keylisteners (GList *key_listeners,
              is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, key_event, ev);
             }          
         }
-      else g_print ("no match for listener %d\n", i);
+      else
+        {
+#ifdef SPI_KEYEVENT_DEBUG
+             g_print ("no match for listener %d\n", i);
+#endif
+             ;
+       }
     }
   return is_consumed;
 }
index cc88dce..75ec325 100644 (file)
@@ -268,11 +268,18 @@ key_set_contains_key (Accessibility_KeySet *key_set, Accessibility_KeyStroke *ke
 
   for (i=0; i<len; ++i)
     {
-      g_print ("key_set[%d] = %d\n", i, (int) key_set->_buffer[i]);
-      if (key_set->_buffer[i] == (CORBA_long) key_event->keyID) return TRUE;       
+#ifdef SPI_KEYEVENT_DEBUG          
+      g_print ("key_set[%d] = %d; key_event %d, code %d\n",
+               i,
+              (int) key_set->_buffer[i],
+              (int) key_event->keyID,
+              (int) key_event->keycode); 
+#endif
+      if (key_set->_buffer[i] == (CORBA_long) key_event->keyID) return TRUE;
+      if (key_set->_buffer[i] == (CORBA_long) -key_event->keycode) return TRUE;
     }
   
-  return TRUE;
+  return FALSE;
 }
 
 static gboolean
@@ -294,7 +301,7 @@ key_eventtype_seq_contains_event (Accessibility_KeyEventTypeSeq *type_seq,
 
   for (i=0; i<len; ++i)
     {
-      g_print ("type_seq[%d] = %d\n", i, (int) type_seq->_buffer[i]);
+/*      g_print ("type_seq[%d] = %d\n", i, (int) type_seq->_buffer[i]); */
       if (type_seq->_buffer[i] == (CORBA_long) key_event->type) return TRUE;       
     }
   
@@ -339,7 +346,13 @@ notify_keylisteners (GList *key_listeners,
              is_consumed = Accessibility_KeystrokeListener_keyEvent (ls, key_event, ev);
             }          
         }
-      else g_print ("no match for listener %d\n", i);
+      else
+        {
+#ifdef SPI_KEYEVENT_DEBUG
+             g_print ("no match for listener %d\n", i);
+#endif
+             ;
+       }
     }
   return is_consumed;
 }
index 0880931..31df81d 100644 (file)
@@ -32,7 +32,7 @@
 #define SHIFT_R_KEYCODE 62
 
 /* these can be increased to access more keys */
-#define MAX_ROWS 5
+#define MAX_ROWS 6 /* The last row only holds Quit and ShiftLatch, special-purpose keys */
 #define MAX_COLUMNS 14
 
 static AccessibleKeystrokeListener *key_listener;
@@ -42,6 +42,187 @@ static boolean shift_latched = False;
 static boolean caps_lock = False;
 static GtkButton **buttons[MAX_ROWS];
 
+typedef enum {
+       SCAN_IDLE,
+       SCAN_LINES,
+       SCAN_LINES_DONE,
+       SCAN_KEYS,
+       SCAN_KEYS_DONE
+} ScanTimerState;
+
+typedef struct {
+       ScanTimerState timer_state;
+       gint scan_row;
+       gint scan_column;
+} ScanState;
+
+GdkColor *
+button_default_bg_color (GtkButton *button)
+{
+  static GdkColor bg_color;
+  static gboolean initialized = FALSE;
+  if (!initialized)
+  {
+    bg_color = gtk_widget_get_style (GTK_WIDGET (button))->bg[GTK_STATE_NORMAL];
+    initialized = TRUE;
+  }
+  return &bg_color;
+}
+
+GdkColor *
+button_default_selected_color (GtkButton *button)
+{
+  static GdkColor selected_color;
+  static gboolean initialized = FALSE;
+  if (!initialized)
+  {
+    selected_color = gtk_widget_get_style (GTK_WIDGET (button))->bg[GTK_STATE_SELECTED];
+    initialized = TRUE;
+  }
+  return &selected_color;
+}
+
+void
+select_key (gint lineno, gint keyno)
+{
+  /*
+   * Before we do this, we need to make sure we've saved the default normal bg.
+   * The button_default_bg_color() call caches this for us (as a side-effect).
+   * Probably we should do this a cleaner way...
+   */
+  button_default_bg_color (buttons [lineno][keyno]);   
+  gtk_widget_modify_bg (GTK_WIDGET (buttons [lineno][keyno]),
+                       GTK_STATE_NORMAL,
+                       button_default_selected_color (buttons [lineno][keyno]));
+}
+
+void
+deselect_key (gint lineno, gint keyno)
+{
+  gtk_widget_modify_bg (GTK_WIDGET (buttons [lineno][keyno]),
+                       GTK_STATE_NORMAL,
+                       button_default_bg_color (buttons [lineno][keyno]));
+}
+
+void
+deselect_line (gint lineno)
+{
+  int i;
+  int max_columns = MAX_COLUMNS;
+  if (lineno == MAX_ROWS-1) max_columns = 2;
+  for (i=0; i<max_columns; ++i)
+         deselect_key (lineno, i);
+}
+
+void
+select_line (gint lineno)
+{
+  int i;
+  int max_columns = MAX_COLUMNS;
+  if (lineno == MAX_ROWS-1) max_columns = 2;
+  for (i=0; i<max_columns; ++i)
+         select_key (lineno, i);
+}
+
+
+static ScanState*
+scan_state ()
+{
+  static ScanState state = {SCAN_IDLE, 0, 0};
+  return &state;
+}
+
+static gboolean
+timeout_scan (gpointer data)
+{
+  ScanState *state = (ScanState *) data;
+  state->timer_state = SCAN_IDLE;
+  deselect_key (state->scan_row, state->scan_column);
+  return FALSE;
+}
+
+static gboolean
+increment_scan (gpointer data)
+{
+  ScanState *state = (ScanState *) data;
+  int max_columns;
+  switch (state->timer_state)
+    {  
+      case SCAN_IDLE: 
+/* happens if switch-break occurs before the timer fires, after SCAN_KEYS_DONE*/
+          return FALSE;
+      case SCAN_LINES:
+          deselect_line (state->scan_row);
+          state->scan_row = (++state->scan_row < MAX_ROWS) ? state->scan_row : 0;
+          select_line (state->scan_row);
+          g_print ("line %d\n", state->scan_row);
+         break;
+      case SCAN_KEYS:
+          deselect_key (state->scan_row, state->scan_column);
+         if (state->scan_row == MAX_ROWS-1) max_columns = 2;
+         else max_columns = MAX_COLUMNS; /* last row has only two keys */
+          state->scan_column = (++state->scan_column < max_columns) ? state->scan_column : 0;
+          select_key (state->scan_row, state->scan_column);
+          g_print ("row %d\n", state->scan_column);
+         break;
+      case SCAN_LINES_DONE:
+      case SCAN_KEYS_DONE:
+         return FALSE;
+      default:
+    }
+  return TRUE;
+}
+
+static void
+scan_start (unsigned int timestamp)
+{
+  ScanState *state = scan_state();
+  switch (state->timer_state)
+    {
+    case SCAN_IDLE:
+      state->timer_state = SCAN_LINES;
+      state->scan_column = 0;
+      state->scan_row = 0;
+      g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 600, increment_scan, state, NULL);
+      select_line (state->scan_row);
+      break;
+    case SCAN_LINES_DONE:
+      state->timer_state = SCAN_KEYS;
+      g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 600, increment_scan, state, NULL);
+      deselect_line (state->scan_row);
+      select_key (state->scan_row, state->scan_column);
+      break;
+    case SCAN_KEYS_DONE:
+      gtk_button_clicked (buttons[state->scan_row][state->scan_column]);
+      deselect_key (state->scan_row, state->scan_column);
+      state->timer_state = SCAN_IDLE;
+      break;
+    default:
+      g_print("unexpected state for 'scan start'\n");
+    }
+}
+
+static void
+scan_stop (unsigned int timestamp)
+{
+  /* find the element correspondin to this event's timestamp */
+  ScanState *state = scan_state();
+  switch (state->timer_state)
+    {
+    case SCAN_LINES:
+      state->timer_state = SCAN_LINES_DONE;
+      break;
+    case SCAN_KEYS:
+      state->timer_state = SCAN_KEYS_DONE;
+      g_timeout_add_full (G_PRIORITY_HIGH_IDLE, 1200, timeout_scan, state, NULL);
+      break;
+    case SCAN_IDLE:
+      break;
+    default:
+      g_print("unexpected state for 'scan stop'\n");
+    }
+}
+
 static void
 label_buttons(boolean shifted)
 {
@@ -52,7 +233,7 @@ label_buttons(boolean shifted)
   char *button_label;
   char *keysymstring;
   
-  for (i=0; i<MAX_ROWS; ++i)
+  for (i=0; i<MAX_ROWS-1; ++i) /* last row doesn't change */
     {
       for (j=0; j<MAX_COLUMNS; ++j, ++keycode)
         {
@@ -88,20 +269,15 @@ show_shift (GtkButton *button, boolean *is_shifted)
 }
 
 static void
-do_shift (GtkButton *button)
-{
-  static KeyCode shift_keycode = 0;
-  if (!shift_keycode) shift_keycode = XKeysymToKeycode(GDK_DISPLAY(), (KeySym) 0xFFE1);
-  /* Note: in a real onscreen keyboard shift keycode should not be hard-coded! */
+toggle_shift_latch (GtkButton *button) 
+{ 
   shift_latched = !shift_latched;
-  generateKeyEvent (shift_keycode, shift_latched ? SPI_KEY_PRESS : SPI_KEY_RELEASE);
   if (buttons) label_buttons (caps_lock || shift_latched);
 }
 
 static void
 keysynth_exit()
 {
-  if (shift_latched) do_shift (NULL);
   deregisterAccessibleKeystrokeListener (key_listener, SPI_KEYMASK_ALT );
   deregisterAccessibleKeystrokeListener (switch_listener, SPI_KEYMASK_UNMODIFIED );
   SPI_exit ();
@@ -152,13 +328,31 @@ is_command_key (void *p)
 static boolean
 switch_callback (void *p)
 {
+  AccessibleKeyStroke *key = (AccessibleKeyStroke *)p;
+  static is_down = FALSE;
+  if (key->type == Accessibility_KEY_RELEASED)
+    {
+      g_print ("spacebar up\n");
+      is_down = FALSE;
+      scan_stop (key->timestamp);
+    }
+  else 
+  if (!is_down)
+    {
+      g_print ("spacebar down\n");
+      is_down = TRUE;
+      scan_start (key->timestamp);
+    }
+  /* catch the first, ignore the rest (will repeat) until keyrelease */
   return FALSE;
 }
 
 static void
 synth_keycode (GtkButton *button, KeyCode *keycode)
 {
-  if (shift_latched) do_shift (button);
+  static KeyCode shift_keycode = 0;
+  if (!shift_keycode) shift_keycode = XKeysymToKeycode(GDK_DISPLAY(), (KeySym) 0xFFE1);
+  /* Note: in a real onscreen keyboard shift keycode should not be hard-coded! */
   if (*keycode)
     {
       if (*keycode == CAPSLOCK_KEYCODE)
@@ -166,8 +360,17 @@ synth_keycode (GtkButton *button, KeyCode *keycode)
           caps_lock = !caps_lock;           
           label_buttons (caps_lock || shift_latched);
         }
+      if (shift_latched)
+             generateKeyEvent (shift_keycode, SPI_KEY_PRESS);
+      
       generateKeyEvent ((long) *keycode, SPI_KEY_PRESSRELEASE);
-    }      
+
+      if (shift_latched)
+        {
+         generateKeyEvent (shift_keycode, SPI_KEY_RELEASE);
+         toggle_shift_latch (button);
+       }
+    }
 }
 
 static void
@@ -197,7 +400,7 @@ create_vkbd()
                              "GtkWidget::parent", window,
                              "GtkWidget::visible", TRUE,
                              NULL);
-  for (i=0; i<MAX_ROWS; ++i)
+  for (i=0; i<MAX_ROWS-1; ++i)
     {
       hbox = gtk_widget_new (gtk_hbox_get_type(),
                             "GtkWidget::parent", container,
@@ -229,22 +432,23 @@ create_vkbd()
                         "GtkWidget::parent", container,
                         "GtkWidget::visible", TRUE,
                         NULL);
-  button = g_object_connect (gtk_widget_new (gtk_button_get_type (),
-                                            "GtkButton::label", "Quit",
-                                            "GtkWidget::parent", hbox,
-                                            "GtkWidget::visible", TRUE,
-                                            NULL),
-                            "signal::clicked",
-                            button_exit, NULL,
-                            NULL);
-  button = g_object_connect (gtk_widget_new (gtk_button_get_type (),
-                                            "GtkButton::label", "ShiftLatch",
-                                            "GtkWidget::parent", hbox,
-                                            "GtkWidget::visible", TRUE,
-                                            NULL),
-                            "signal::clicked",
-                            do_shift, NULL,
-                            NULL);
+  buttons[i] = g_new0 (GtkButton*, 2);
+  buttons[i][0] = g_object_connect (gtk_widget_new (gtk_button_get_type (),
+                                                            "GtkButton::label", "Quit",
+                                                            "GtkWidget::parent", hbox,
+                                                            "GtkWidget::visible", TRUE,
+                                                            NULL),
+                                            "signal::clicked",
+                                            button_exit, NULL,
+                                            NULL);
+  buttons[i][1] = g_object_connect (gtk_widget_new (gtk_button_get_type (),
+                                                   "GtkButton::label", "ShiftLatch",
+                                                   "GtkWidget::parent", hbox,
+                                                   "GtkWidget::visible", TRUE,
+                                                   NULL),
+                                   "signal::clicked",
+                                   toggle_shift_latch, NULL,
+                                   NULL);
   label_buttons (caps_lock || shift_latched);
   gtk_widget_show (window);
 }
@@ -252,7 +456,7 @@ create_vkbd()
 int
 main(int argc, char **argv)
 {
-  AccessibleKeySet spacebar_set;
+  AccessibleKeySet switch_set;
   
   if ((argc > 1) && (!strncmp(argv[1],"-h",2)))
   {
@@ -273,19 +477,23 @@ main(int argc, char **argv)
                                      SPI_KEYLISTENER_CANCONSUME | SPI_KEYLISTENER_ALL_WINDOWS);
   create_vkbd();  
 
-  /* register a listener on the spacebar, to serve as a 'single switch' */
-  spacebar_set.keysyms = g_new0 (unsigned long, 1);
-  spacebar_set.keycodes = g_new0 (unsigned short, 1);
-  spacebar_set.len = 1;
-  spacebar_set.keysyms[0] = (unsigned long) ' ';
-  spacebar_set.keycodes[0] = (unsigned short) 0;
+  /*
+   * Register a listener on an 'unused' key, to serve as a 'single switch'.
+   * On most Intel boxes there is at least one 'special' system key that does not
+   * have a non-zero keycode assigned in the Xserver, so we will intercept any keycode
+   * that is 'zero'.  Often these the "windows" key or the "menu" key.
+   */
+  switch_set.keysyms = g_new0 (unsigned long, 1);
+  switch_set.keycodes = g_new0 (unsigned short, 1);
+  switch_set.len = 1;
+  switch_set.keysyms[0] = (unsigned long) 0;
+  switch_set.keycodes[0] = (unsigned short) 0;
   switch_listener = createAccessibleKeystrokeListener(switch_callback);
-  /* registerKeystrokeListener(switch_listener,
-                           &spacebar_set,
-                           SPI_KEYMASK_UNMODIFIED,
-                           (unsigned long) ( KeyPress | KeyRelease),
-                           SPI_KEYLISTENER_CANCONSUME);
-  */
+  registerAccessibleKeystrokeListener(switch_listener,
+                                     &switch_set,
+                                     SPI_KEYMASK_UNMODIFIED,
+                                     (unsigned long) ( KeyPress | KeyRelease),
+                                     SPI_KEYLISTENER_CANCONSUME);
   
   SPI_event_main(TRUE);
 }
index f707a80..f8fe2e4 100644 (file)
@@ -1,4 +1,4 @@
-#include <stdio.h>
+
 #include <stdlib.h>
 #include <libbonobo.h>
 #include "Magnifier.h"
index 122f8d3..6ca08b7 100644 (file)
@@ -42,6 +42,8 @@ xlib_colormap * x_cmap;
 typedef struct _MagnifierData {
        int mag_width;
        int mag_height;
+       int mag_x;
+       int mag_y;
        int factor_x;
        int factor_y;
        point center;
index 94a0889..781a038 100644 (file)
@@ -70,6 +70,37 @@ struct poptOption magnifier_options [] = {
 
 #define MSG_LEN 80
 
+static GtkWidget *window; /* TODO: clean up, with accessor func? */
+
+static void
+magnifier_realize (GtkWidget *widget)
+{
+  XWMHints wm_hints;
+  Atom wm_window_protocols[2];
+  static gboolean initialized = FALSE;
+  
+  if (!initialized)
+    {
+      wm_window_protocols[0] = gdk_x11_get_xatom_by_name ("WM_DELETE_WINDOW");
+      wm_window_protocols[1] = gdk_x11_get_xatom_by_name ("_NET_WM_PING");
+    }
+  
+  wm_hints.flags = InputHint;
+  wm_hints.input = False;
+  
+  XSetWMHints (GDK_WINDOW_XDISPLAY (widget->window),
+              GDK_WINDOW_XWINDOW (widget->window), &wm_hints);
+  
+  XSetWMProtocols (GDK_WINDOW_XDISPLAY (widget->window),
+                  GDK_WINDOW_XWINDOW (widget->window), wm_window_protocols, 2);
+}
+
+static void
+magnifier_exit()
+{
+  gtk_exit(0);
+}
+
 static gboolean get_commands(GIOChannel* client,
                             GIOCondition condition,
                             gpointer data){
@@ -89,7 +120,6 @@ static gboolean get_commands(GIOChannel* client,
 }
 
 int main (int argc, char** argv){
-  GtkWidget *window;
   GIOChannel *mag_channel;
   char *dpyname;
   char env_string[ENV_STRING_MAX_SIZE];
@@ -127,7 +157,19 @@ int main (int argc, char** argv){
   }
   gtk_init (&argc, &argv);
 
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  window = g_object_connect (gtk_widget_new (gtk_window_get_type (),
+                                            "user_data", NULL,
+                                            "can_focus", FALSE,
+                                            "type", GTK_WINDOW_TOPLEVEL,
+                                            "title", "magnifier",
+                                            "allow_grow", FALSE,
+                                            "allow_shrink", FALSE,
+                                            "border_width", 10,
+                                            NULL),
+                            "signal::realize", magnifier_realize, NULL,
+                            "signal::destroy", magnifier_exit, NULL,
+                            NULL);
+  
   drawing_area = gtk_drawing_area_new();
   gtk_container_add (GTK_CONTAINER (window),drawing_area);
   gtk_widget_add_events(GTK_WIDGET(drawing_area),GDK_BUTTON_PRESS_MASK);
@@ -197,6 +239,7 @@ int main (int argc, char** argv){
   if (global_options.horizontal_split)
          magnifier->mag_data->mag_height = DisplayHeight (magnifier->mag_data->target_display,screen_num)/2;
   else magnifier->mag_data->mag_height = DisplayHeight (magnifier->mag_data->target_display, screen_num);
+  gtk_window_set_decorated(GTK_WINDOW (window), FALSE);
   gtk_widget_show_all (window);
 
   gdk_window_move(window->window,
@@ -205,7 +248,6 @@ int main (int argc, char** argv){
   gdk_window_resize (window->window, magnifier->mag_data->mag_width, magnifier->mag_data->mag_height);
   magnifier->mag_data->output_window = window;
   if (global_options.fullscreen) gdk_window_stick (window->window);
-  gtk_window_set_decorated(GTK_WINDOW (window), FALSE);
   gdk_window_set_functions(window->window, 0);
   gdk_window_raise(window->window);
   
@@ -234,6 +276,9 @@ static void
 impl_magnifier_fullscreen (PortableServer_Servant servant,
                           CORBA_Environment *ev)
 {
+  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+  magnifier->mag_data->mag_width = DisplayWidth (magnifier->mag_data->target_display, screen_num);
+  magnifier->mag_data->mag_height = DisplayHeight (magnifier->mag_data->target_display, screen_num);
 }
                                   
 static void
@@ -244,6 +289,10 @@ impl_magnifier_set_extents (PortableServer_Servant servant,
                            CORBA_long y2,
                            CORBA_Environment *ev)
 {
+  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+  magnifier->mag_data->mag_width = x2 - x1;
+  magnifier->mag_data->mag_height = y2 - y1;
+  gdk_window_move(window->window, x1, y1);
 }
 
 static void
@@ -316,8 +365,11 @@ impl_magnifier_set_mag_factor (PortableServer_Servant servant,
                               CORBA_Environment *ev)
 {
   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
-  magnifier->mag_data->factor_x = (float) mag_factor_x;
-  magnifier->mag_data->factor_y = (float) mag_factor_y;
+  if (zoom_region == (CORBA_short) 0) /* TODO: fix for multi-zoom-regions */
+    {
+      magnifier->mag_data->factor_x = (float) mag_factor_x;
+      magnifier->mag_data->factor_y = (float) mag_factor_y;
+    }
 }
 
 static void
@@ -326,6 +378,7 @@ impl_magnifier_mark_dirty (PortableServer_Servant servant,
                           CORBA_Environment *ev)
 {
   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+  /* TODO: implement */
 }
 
 static void
@@ -334,6 +387,7 @@ impl_magnifier_mark_unmanaged (PortableServer_Servant servant,
                               CORBA_Environment *ev)
 {
   Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+  /* TODO: implement */
 }
 
 static CORBA_short
@@ -351,7 +405,7 @@ impl_magnifier_create_zoom_region (PortableServer_Servant servant,
 }
 
 static CORBA_boolean
-impl_magnifier_get_zoom_region_params (PortableServer_Servant _servant,
+impl_magnifier_get_zoom_region_params (PortableServer_Servant servant,
                                       const CORBA_short zoom_region,
                                       CORBA_float * zx,
                                       CORBA_float * zy, CORBA_long * x1,
@@ -359,7 +413,18 @@ impl_magnifier_get_zoom_region_params (PortableServer_Servant _servant,
                                       CORBA_long * y2,
                                       CORBA_Environment * ev)
 {
-       return CORBA_FALSE;
+  Magnifier *magnifier = MAGNIFIER (bonobo_object_from_servant (servant));
+  if (zoom_region == (CORBA_short) 0)
+  {
+    *zx = magnifier->mag_data->factor_x;
+    *zy = magnifier->mag_data->factor_y;
+    *x1 = 0;
+    *y1 = 0;
+    *x2 = *x1 + magnifier->mag_data->mag_width;
+    *y2 = *y1 + magnifier->mag_data->mag_height;
+    return CORBA_TRUE;   
+  }
+  else return CORBA_FALSE;
 }
 
 static void