Major rework of the x11 simulator button handling. (1) Button repeat should always work correctly now, not sending a release before the repeat(s). Fixes e.g. calling the Ondio menu. (2) Button handling is done in the timer thread, not sleep()ing the main thread for extended times. Fixes slow performance of high-workload plugins (codec tests). (3) The x11 simulator now also contains the queue handling code. (4) The new code requires X11R6 because the multi-threading extension is used.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6215 a1c6a512-1295-4272-9138-f99709370657
diff --git a/uisimulator/x11/SOURCES b/uisimulator/x11/SOURCES
index ea60b4e..c481370 100644
--- a/uisimulator/x11/SOURCES
+++ b/uisimulator/x11/SOURCES
@@ -1,4 +1,5 @@
 button-x11.c
+kernel.c
 lcd-x11.c
 #if 0 /* if sound is enabled */
 oss_sound.c
diff --git a/uisimulator/x11/button-x11.c b/uisimulator/x11/button-x11.c
index 28ede95..593d926 100644
--- a/uisimulator/x11/button-x11.c
+++ b/uisimulator/x11/button-x11.c
@@ -16,6 +16,7 @@
  * KIND, either express or implied.
  *
  ****************************************************************************/
+#include <stdlib.h>
 #include "config.h"
 #include "button.h"
 #include "kernel.h"
@@ -24,41 +25,122 @@
 
 #include "X11/keysym.h"
 
-/*
- *Initialize buttons
- */
-void button_init()
+extern int screenhack_handle_events(bool *release);
+
+struct event_queue button_queue;
+
+static int button_state = 0; /* keeps track of pressed keys */
+static long lastbtn;   /* Last valid button status */
+
+/* how often we check to see if a button is pressed */
+#define POLL_FREQUENCY    HZ/25
+
+/* how long until repeat kicks in */
+#define REPEAT_START      8
+
+/* the speed repeat starts at */
+#define REPEAT_INTERVAL_START   4
+
+/* speed repeat finishes at */
+#define REPEAT_INTERVAL_FINISH  2
+
+/* mostly copied from real button.c */
+void button_read (void);
+
+void button_tick(void)
 {
+    static int tick = 0;
+    static int count = 0;
+    static int repeat_speed = REPEAT_INTERVAL_START;
+    static int repeat_count = 0;
+    static bool repeat = false;
+    int diff;
+    int btn;
+
+    /* only poll every X ticks */
+    if ( ++tick >= POLL_FREQUENCY )
+    {
+        bool post = false;
+        button_read();
+        btn = button_state;
+
+        /* Find out if a key has been released */
+        diff = btn ^ lastbtn;
+        if(diff && (btn & diff) == 0)
+        {
+            queue_post(&button_queue, BUTTON_REL | diff, NULL);
+        }
+        else
+        {
+            if ( btn )
+            {
+                /* normal keypress */
+                if ( btn != lastbtn )
+                {
+                    post = true;
+                    repeat = false;
+                    repeat_speed = REPEAT_INTERVAL_START;
+
+                }
+                else /* repeat? */
+                {
+                    if ( repeat )
+                    {
+                        count--;
+                        if (count == 0) {
+                            post = true;
+                            /* yes we have repeat */
+                            repeat_speed--;
+                            if (repeat_speed < REPEAT_INTERVAL_FINISH)
+                                repeat_speed = REPEAT_INTERVAL_FINISH;
+                            count = repeat_speed;
+
+                            repeat_count++;
+
+                        }
+                    }
+                    else
+                    {
+                        if (count++ > REPEAT_START)
+                        {
+                            post = true;
+                            repeat = true;
+                            repeat_count = 0;
+                            /* initial repeat */
+                            count = REPEAT_INTERVAL_START;
+                        }
+                    }
+                }
+                if ( post )
+                {
+                    if (repeat)
+                        queue_post(&button_queue, BUTTON_REPEAT | btn, NULL);
+                    else
+                        queue_post(&button_queue, btn, NULL);
+                }
+            }
+            else
+            {
+                repeat = false;
+                count = 0;
+            }
+        }
+        lastbtn = btn & ~(BUTTON_REL | BUTTON_REPEAT);
+        tick = 0;
+    }
 }
 
 /*
- * Translate X keys to Recorder keys
- *
- * We simulate recorder keys on the numeric keypad:
- *
- * 4,6,8,2 = Left, Right, Up, Down
- * 5 = Play/pause
- * Div,Mul,Sub = The tree menu keys
- * +,Enter = On, Off
- *
- * Alternative Keys For Laptop or VNC Users
- * Recorder:
- * Space=Play Q=On A=Off 1,2,3 = F1,F2,F3
- * Player:
- * Q=On Return=Menu
+ * Read X keys and translate to rockbox buttons
  */
 
-extern int screenhack_handle_events(bool *release, bool *repeat);
-
-int button_state = 0;
-
-static int get_raw_button (void)
+void button_read (void)
 {
     int k;
-    bool release=false; /* is this a release event */
-    bool repeat=false;  /* is the key a repeated one */
-    int ev=screenhack_handle_events(&release, &repeat);
-    switch(ev)
+    bool release = false; /* is this a release event */
+    int ev = screenhack_handle_events(&release);
+
+    switch (ev)
     {
         case XK_KP_Left:
         case XK_Left:
@@ -144,10 +226,7 @@
 #ifdef HAVE_LCD_BITMAP
         case XK_5:
             if(!release)
-            {
                 screen_dump();
-                return 0;
-            }
             break;
 #endif
 
@@ -168,75 +247,45 @@
             break;
     }
 
-    if(release) {
-        /* return a release event */
+    if (release)
         button_state &= ~k;
-        k |= BUTTON_REL;
-    } 
-    else {
-        if(k) {
-            button_state |= k;
-            k = button_state;
-        }
-    }
-
-    if(repeat)
-        k |= BUTTON_REPEAT;
-    return k;
+    else
+        button_state |= k;
 }
 
-/*
- * Timeout after TICKS unless a key is pressed.
- */
-long button_get_w_tmo(int ticks)
-{
-    int bits;
-    int i=0;
+/* Again copied from real button.c... */
 
-    for(i=0; i< ticks; i++) {
-        bits = get_raw_button();
-        if(!bits)
-            sim_sleep(1);
-        else
-            break;
-    }
-
-    return bits;
-}
-
-/*
- * Get the currently pressed button.
- * Returns one of BUTTON_xxx codes, with possibly a modifier bit set.
- * No modifier bits are set when the button is first pressed.
- * BUTTON_HELD bit is while the button is being held.
- * BUTTON_REL bit is set when button has been released.
- */
 long button_get(bool block)
 {
-    int bits;
-    do {
-        bits = get_raw_button();
-        if(block && !bits)
-            sim_sleep(HZ/10);
-        else
-            break;
-    } while(1);
+    struct event ev;
 
-    if(!block)
-        /* delay a bit */
-        sim_sleep(1);
+    if ( block || !queue_empty(&button_queue) ) 
+    {
+        queue_wait(&button_queue, &ev);
+        return ev.id;
+    }
+    return BUTTON_NONE;
+}
 
-    return bits;
+long button_get_w_tmo(int ticks)
+{
+    struct event ev;
+    queue_wait_w_tmo(&button_queue, &ev, ticks);
+    return (ev.id != SYS_TIMEOUT)? ev.id: BUTTON_NONE;
+} 
+
+void button_init(void)
+{
 }
 
 int button_status(void)
 {
-    return get_raw_button();
+    return lastbtn;
 }
 
 void button_clear_queue(void)
 {
-    while (get_raw_button());
+    queue_clear(&button_queue);
 }
 
 #if CONFIG_KEYPAD == IRIVER_H100_PAD
diff --git a/uisimulator/x11/kernel.c b/uisimulator/x11/kernel.c
new file mode 100644
index 0000000..7405fec
--- /dev/null
+++ b/uisimulator/x11/kernel.c
@@ -0,0 +1,108 @@
+/***************************************************************************
+ *             __________               __   ___.
+ *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+ *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+ *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+ *                     \/            \/     \/    \/            \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Jens Arnold
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "kernel.h"
+#include "thread.h"
+
+int set_irq_level (int level)
+{
+    static int _lv = 0;
+    return (_lv = level);
+}
+
+void queue_init(struct event_queue *q)
+{
+    q->read = 0;
+    q->write = 0;
+}
+
+void queue_wait(struct event_queue *q, struct event *ev)
+{
+    while(q->read == q->write)
+    {
+        switch_thread();
+    }
+
+    *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
+}
+
+void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
+{
+    unsigned int timeout = current_tick + ticks;
+
+    while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
+    {
+        sleep(1);
+    }
+
+    if(q->read != q->write)
+    {
+        *ev = q->events[(q->read++) & QUEUE_LENGTH_MASK];
+    }
+    else
+    {
+        ev->id = SYS_TIMEOUT;
+    }
+}
+
+void queue_post(struct event_queue *q, long id, void *data)
+{
+    int wr;
+    int oldlevel;
+
+    oldlevel = set_irq_level(15<<4);
+    wr = (q->write++) & QUEUE_LENGTH_MASK;
+
+    q->events[wr].id = id;
+    q->events[wr].data = data;
+    set_irq_level(oldlevel);
+}
+
+bool queue_empty(const struct event_queue* q)
+{
+    return ( q->read == q->write );
+}
+
+void queue_clear(struct event_queue* q)
+{
+    /* fixme: This is potentially unsafe in case we do interrupt-like processing */
+    q->read = 0;
+    q->write = 0;
+}
+
+void switch_thread (void)
+{
+    yield ();
+}
+
+void mutex_init(struct mutex *m)
+{
+    (void)m;
+}
+
+void mutex_lock(struct mutex *m)
+{
+    (void)m;
+}
+
+void mutex_unlock(struct mutex *m)
+{
+    (void)m;
+}
+
diff --git a/uisimulator/x11/lcd-x11.c b/uisimulator/x11/lcd-x11.c
index be687d1..dada13d 100644
--- a/uisimulator/x11/lcd-x11.c
+++ b/uisimulator/x11/lcd-x11.c
@@ -42,7 +42,6 @@
 
 extern unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH];
 extern void screen_resized(int width, int height);
-extern Display *dpy;
 
 #ifdef HAVE_LCD_BITMAP
 unsigned char lcd_framebuffer_copy[LCD_HEIGHT/8][LCD_WIDTH];
@@ -91,9 +90,11 @@
 
     drawdots(0, &clearpoints[0], cp);
     drawdots(1, &points[0], p);
-/* printf("lcd_update: Draws %d pixels, clears %d pixels (max %d/%d)\n", 
+    /* printf("lcd_update: Draws %d pixels, clears %d pixels (max %d/%d)\n",
        p, cp, p+cp, LCD_HEIGHT*LCD_WIDTH); */
+    XtAppLock(app);
     XSync(dpy,False);
+    XtAppUnlock(app);
 }
 
 void lcd_update_rect(int x_start, int y_start,
@@ -117,7 +118,7 @@
     /* The Y coordinates have to work on even 8 pixel rows */
     ymax = (yline + height)/8;
     yline /= 8;
- 
+
     xmax = x_start + width;
 
     if(xmax > LCD_WIDTH)
@@ -156,8 +157,10 @@
 
     drawdots(0, &clearpoints[0], cp);
     drawdots(1, &points[0], p);
-   /* printf("lcd_update_rect: Draws %d pixels, clears %d pixels\n", p, cp);*/
+    /* printf("lcd_update_rect: Draws %d pixels, clears %d pixels\n", p, cp);*/
+    XtAppLock(app);
     XSync(dpy,False);
+    XtAppUnlock(app);
 }
 #endif
 #ifdef HAVE_LCD_CHARCELLS
@@ -186,7 +189,11 @@
         }
     }
     if (changed)
+    {
+        XtAppLock(app);
         XSync(dpy,False);
+        XtAppUnlock(app);
+    }
     lcd_display_redraw=false;
 }
 
diff --git a/uisimulator/x11/screenhack.c b/uisimulator/x11/screenhack.c
index d7f21a6..d8731e4 100644
--- a/uisimulator/x11/screenhack.c
+++ b/uisimulator/x11/screenhack.c
@@ -125,6 +125,8 @@
 char *progname;
 XrmDatabase db;
 XtAppContext app;
+Display* dpy;
+Window window;
 Bool mono_p;
 
 static XrmOptionDescRec default_options [] = {
@@ -155,8 +157,8 @@
     0
 };
 
-extern Display* dpy;
 extern int display_zoom;
+extern long current_tick;
 
 static XrmOptionDescRec *merged_options;
 static int merged_options_size;
@@ -238,27 +240,23 @@
 
 static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW;
 
-static Bool checkrepeat(time_t prev,
-                       time_t now)
+
+void kb_disable_auto_repeat(bool on)
 {
-    if(now-prev < 50) {
-        return true;
-    }
-    return false;
+    XKeyboardControl kb;
+
+    kb.auto_repeat_mode = on ? AutoRepeatModeOff : AutoRepeatModeDefault;
+    XChangeKeyboardControl(dpy, KBAutoRepeatMode, &kb);
 }
 
 /* Dead-trivial event handling.
    Exit if the WM_PROTOCOLS WM_DELETE_WINDOW ClientMessage is received.
  */
-int screenhack_handle_event(Display *dpy, XEvent *event,
-                            bool *release, bool *repeat)
+int screenhack_handle_event(XEvent *event, bool *release)
 {
     int key=0;
-    static time_t lasttime;
-    static unsigned int lastkeycode;
 
     *release = FALSE;
-    *repeat = false;
 
     switch (event->xany.type) {
         case KeyPress:
@@ -268,14 +266,9 @@
                 XLookupString (&event->xkey, &c, 1, &keysym, 0);
                 key = keysym;
 #if 0
-                DEBUGF("Got keypress: %02x %x, time %lx\n", c,
-                       event->xkey.keycode,
-                       event->xkey.time);
+                DEBUGF("Got keypress: %c (%02x) %x, tick %ld\n", c, c,
+                       event->xkey.keycode, current_tick);
 #endif
-                if(lastkeycode == event->xkey.keycode)
-                    *repeat = checkrepeat(lasttime, event->xkey.time);
-                lasttime = event->xkey.time;
-                lastkeycode = event->xkey.keycode;
             }
             break;
         case KeyRelease:
@@ -285,22 +278,21 @@
                 XLookupString (&event->xkey, &c, 1, &keysym, 0);
                 key = keysym;
 #if 0
-                DEBUGF("Got keyrelease: %c (%02x) %x\n", c, c,
-                       event->xkey.keycode);
+                DEBUGF("Got keyrelease: %c (%02x) %x, tick %ld\n", c, c,
+                       event->xkey.keycode, current_tick);
 #endif
-                if(lastkeycode == event->xkey.keycode)
-                    *repeat = checkrepeat(lasttime, event->xkey.time);
-                lasttime = event->xkey.time;
-                lastkeycode = event->xkey.keycode;
-                if(*repeat)
-                    return 0; /* on repeats, return nothing on release */
-              
                 *release = TRUE;
             }
             break;
         case Expose:
             screen_redraw();
             break;
+        case FocusIn:
+            kb_disable_auto_repeat(true);
+            break;
+        case FocusOut:
+            kb_disable_auto_repeat(false);
+            break;
         case ClientMessage:
             if (event->xclient.message_type != XA_WM_PROTOCOLS) {
                 char *s = XGetAtomName(dpy, event->xclient.message_type);
@@ -320,6 +312,8 @@
                          progname, s1, s2);
             }
             else {
+                kb_disable_auto_repeat(false);
+                XSync(dpy, false); /* force the X server to process that */
                 exit (0);
             }
             break;
@@ -330,15 +324,17 @@
 }
 
 
-int screenhack_handle_events(bool *release, bool *repeat)
+int screenhack_handle_events(bool *release)
 {
     int key=0;
+    XtAppLock(app);
     if(XPending(dpy))
     {
         XEvent event;
         XNextEvent(dpy, &event);
-        key=screenhack_handle_event(dpy, &event, release, repeat);
+        key=screenhack_handle_event(&event, release);
     }
+    XtAppUnlock(app);
     return key;
 }
 
@@ -347,7 +343,7 @@
 {
 #ifdef USE_GL
     /* If we're linking against GL (that is, this is the version of 
-       screenhack.o that the GL hacks will use, which is different from the 
+       screenhack.o that the GL hacks will use, which is different from the
        one that the non-GL hacks will use) then try to pick the "best" visual 
        by interrogating the GL library instead of by asking Xlib.  GL knows 
        better.
@@ -379,8 +375,6 @@
 int main (int argc, char **argv)
 {
     Widget toplevel;
-    Display *dpy;
-    Window window;
     Screen *screen;
     Visual *visual;
     Colormap cmap;
@@ -460,9 +454,11 @@
        does work when passed as an -xrm arg on the command line.  So screw it,
        turn them off from C instead.
     */
-    SgiUseSchemes ("none"); 
+    SgiUseSchemes ("none");
 #endif /* __sgi */
 
+    XtToolkitThreadInitialize();
+
     toplevel = XtAppInitialize (&app, progclass, merged_options,
                                 merged_options_size, &argc, argv,
                                 merged_defaults, 0, 0);
@@ -556,7 +552,7 @@
             XGetWindowAttributes (dpy, window, &xgwa);
             XSelectInput (dpy, window, 
                           xgwa.your_event_mask | KeyPressMask | KeyRelease |
-                          ButtonPressMask | ExposureMask);
+                          ButtonPressMask | ExposureMask | FocusChangeMask );
             XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32,
                              PropModeReplace,
                              (unsigned char *) &XA_WM_DELETE_WINDOW, 1);
@@ -573,6 +569,7 @@
 
     XSync (dpy, False);
 
-    screenhack (dpy, window); /* doesn't return */
+    kb_disable_auto_repeat(true);
+    screenhack(); /* doesn't return */
     return 0;
 }
diff --git a/uisimulator/x11/screenhack.h b/uisimulator/x11/screenhack.h
index 084f876..5c2e532 100644
--- a/uisimulator/x11/screenhack.h
+++ b/uisimulator/x11/screenhack.h
@@ -28,6 +28,7 @@
 #include <X11/Xlib.h>
 #include <X11/Xresource.h>
 #include <X11/Xos.h>
+#include <X11/Intrinsic.h>
 
 #include "resources.h"
 #include "visual.h"
@@ -38,10 +39,13 @@
 extern XrmDatabase db;
 extern XrmOptionDescRec options [];
 extern char *defaults [];
+extern XtAppContext app;
+extern Display* dpy;
+extern Window window;
 
-extern void screenhack (Display*,Window);
-extern int screenhack_handle_event(Display*, XEvent*, bool *, bool *);
-extern int screenhack_handle_events(bool *, bool *);
+extern void screenhack();
+extern int screenhack_handle_event(XEvent*, bool *);
+extern int screenhack_handle_events(bool *);
 extern void screen_redraw();
 extern void screen_resized();
 
diff --git a/uisimulator/x11/thread.c b/uisimulator/x11/thread.c
index 6f109a3..12a3b3e 100644
--- a/uisimulator/x11/thread.c
+++ b/uisimulator/x11/thread.c
@@ -24,6 +24,16 @@
 #include <sys/time.h>
 
 long current_tick = 0;
+extern void button_tick(void);
+
+static void msleep(int msec)
+{
+    struct timeval delay;
+    
+    delay.tv_sec = msec / 1000;
+    delay.tv_usec = (msec - 1000 * delay.tv_sec) * 1000;
+    select(0, NULL, NULL, NULL, &delay); /* portable sub-second sleep */
+}
 
 /*
  * This is not a target thread, so it does not fall under the 1 thread at a
@@ -31,17 +41,23 @@
  */
 static void update_tick_thread()
 {
-    struct timeval start, now, delay;
+    struct timeval start, now;
+    long new_tick;
 
     gettimeofday(&start, NULL);
     while (1)
     {
-        delay.tv_sec = 0;
-        delay.tv_usec = (1000000/HZ/4);  /* check 4 times per target tick */
-        select(0, NULL, NULL, NULL, &delay); /* portable sub-second sleep */
+        msleep(5); /* check twice per simulated target tick */
         gettimeofday(&now, NULL);
-        current_tick = (now.tv_sec - start.tv_sec) * HZ
-                     + (now.tv_usec - start.tv_usec) * HZ / 1000000;
+        new_tick = (now.tv_sec - start.tv_sec) * HZ
+                   + (now.tv_usec - start.tv_usec) / (1000000/HZ);
+        if (new_tick > current_tick)
+        {
+            current_tick = new_tick;
+            button_tick();  /* Dirty call to button.c. This should probably
+                             * be implemented as a tick task the same way 
+                             * as on the target. */
+        }
     }
 }
 
@@ -73,7 +89,8 @@
 void yield(void)
 {
     pthread_mutex_unlock(&mp); /* return */
-    pthread_mutex_lock(&mp); /* get it again */
+    msleep(1);                 /* prevent busy loop */
+    pthread_mutex_lock(&mp);   /* get it again */
 }
 
 void newfunc(void (*func)(void))
@@ -109,26 +126,8 @@
 
 void sim_sleep(int ticks)
 {
-    struct timeval delay;
-
     pthread_mutex_unlock(&mp); /* return */
-    delay.tv_sec = ticks / HZ;
-    delay.tv_usec = (ticks - HZ * delay.tv_sec) * (1000000/HZ);
-    select(0, NULL, NULL, NULL, &delay);   /* portable subsecond sleep */
-    pthread_mutex_lock(&mp); /* get it again */
+    msleep((1000/HZ) * ticks);
+    pthread_mutex_lock(&mp);   /* get it again */
 }
 
-void mutex_init(struct mutex *m)
-{
-    (void)m;
-}
-
-void mutex_lock(struct mutex *m)
-{
-    (void)m;
-}
-
-void mutex_unlock(struct mutex *m)
-{
-    (void)m;
-}
diff --git a/uisimulator/x11/uibasic.c b/uisimulator/x11/uibasic.c
index ca3c2c5..0c3e9bb 100644
--- a/uisimulator/x11/uibasic.c
+++ b/uisimulator/x11/uibasic.c
@@ -48,9 +48,6 @@
 static Colormap cmap;
 
 int display_zoom=1;
-
-Display *dpy;
-Window window;
 bool lcd_display_redraw=true;
 
 XrmOptionDescRec options [] = {
@@ -96,16 +93,19 @@
     maxx = width;
     maxy = height;
 
+    XtAppLock(app);
     XSetForeground(dpy, draw_gc,
                    get_pixel_resource("background", "Background", dpy, cmap));
     XFillRectangle(dpy, window, draw_gc, 0, 0, width*display_zoom,
                    height*display_zoom);
+    XtAppUnlock(app);
     lcd_display_redraw=true;
     screen_redraw();
 }
 
 void drawrect(int color, int x1, int y1, int x2, int y2)
 {
+    XtAppLock(app);
     if (color==0)
         XSetForeground(dpy, draw_gc,
                        get_pixel_resource("background", "Background", dpy, cmap));
@@ -115,6 +115,7 @@
 
     XFillRectangle(dpy, window, draw_gc, x1*display_zoom, y1*display_zoom,
                    x2*display_zoom, y2*display_zoom);
+    XtAppUnlock(app);
 }
 
 static void help(void)
@@ -125,6 +126,7 @@
 
 void drawline(int color, int x1, int y1, int x2, int y2)
 {
+    XtAppLock(app);
     if (color==0)
         XSetForeground(dpy, draw_gc,
                        get_pixel_resource("background", "Background", dpy, cmap));
@@ -137,10 +139,12 @@
               (int)(y1*display_zoom),
               (int)(x2*display_zoom),
               (int)(y2*display_zoom));
+    XtAppUnlock(app);
 }
 
 void drawdot(int color, int x, int y)
 {
+    XtAppLock(app);
     if (color==0)
         XSetForeground(dpy, draw_gc,
                        get_pixel_resource("background", "Background", dpy, cmap));
@@ -150,10 +154,12 @@
 
     XFillRectangle(dpy, window, draw_gc, x*display_zoom, y*display_zoom,
                    display_zoom, display_zoom);
+    XtAppUnlock(app);
 }
 
 void drawdots(int color, struct coordinate *points, int count)
 {
+    XtAppLock(app);
     if (color==0)
         XSetForeground(dpy, draw_gc,
                        get_pixel_resource("background", "Background", dpy, cmap));
@@ -168,10 +174,12 @@
                        display_zoom,
                        display_zoom);
     }
+    XtAppUnlock(app);
 }
 
 void drawrectangles(int color, struct rectangle *points, int count)
 {
+    XtAppLock(app);
     if (color==0)
         XSetForeground(dpy, draw_gc,
                        get_pixel_resource("background", "Background", dpy, cmap));
@@ -186,10 +194,12 @@
                        points[count].width*display_zoom,
                        points[count].height*display_zoom);
     }
+    XtAppUnlock(app);
 }
 
 void drawtext(int color, int x, int y, char *text)
 {
+    XtAppLock(app);
     if (color==0)
         XSetForeground(dpy, draw_gc,
                        get_pixel_resource("background", "Background", dpy, cmap));
@@ -199,13 +209,13 @@
 
     XDrawString(dpy, window, draw_gc, x*display_zoom, y*display_zoom, text,
                 strlen(text));
+    XtAppUnlock(app);
 }
 
 /* this is where the applicaton starts */
 extern void app_main(void);
 
-void
-screenhack (Display *the_dpy, Window the_window)
+void screenhack()
 {
     Bool helpme;
 
@@ -216,9 +226,6 @@
 
     printf(PROGNAME " " ROCKBOXUI_VERSION " (" __DATE__ ")\n");
 
-    dpy=the_dpy;
-    window=the_window;
-
     init_window();
 
     screen_redraw();