Apply our FLTK extensions


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4605 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/fltk/src/Fl.cxx b/common/fltk/src/Fl.cxx
index 900ff8f..b0cb020 100644
--- a/common/fltk/src/Fl.cxx
+++ b/common/fltk/src/Fl.cxx
@@ -79,6 +79,8 @@
 extern double fl_mac_flush_and_wait(double time_to_wait, char in_idle);
 #endif // WIN32
 
+extern void fl_update_focus(void);
+
 //
 // Globals...
 //
@@ -444,6 +446,69 @@
 #endif
 
 ////////////////////////////////////////////////////////////////
+// Clipboard notifications
+
+struct Clipboard_Notify {
+  Fl_Clipboard_Notify_Handler handler;
+  void *data;
+  struct Clipboard_Notify *next;
+};
+
+static struct Clipboard_Notify *clip_notify_list = NULL;
+
+extern void fl_clipboard_notify_change(); // in Fl_<platform>.cxx
+
+void Fl::add_clipboard_notify(Fl_Clipboard_Notify_Handler h, void *data) {
+  struct Clipboard_Notify *node;
+
+  remove_clipboard_notify(h);
+
+  node = new Clipboard_Notify;
+
+  node->handler = h;
+  node->data = data;
+  node->next = clip_notify_list;
+
+  clip_notify_list = node;
+
+  fl_clipboard_notify_change();
+}
+
+void Fl::remove_clipboard_notify(Fl_Clipboard_Notify_Handler h) {
+  struct Clipboard_Notify *node, **prev;
+
+  node = clip_notify_list;
+  prev = &clip_notify_list;
+  while (node != NULL) {
+    if (node->handler == h) {
+      *prev = node->next;
+      delete node;
+
+      fl_clipboard_notify_change();
+
+      return;
+    }
+
+    prev = &node->next;
+    node = node->next;
+  }
+}
+
+bool fl_clipboard_notify_empty(void) {
+  return clip_notify_list == NULL;
+}
+
+void fl_trigger_clipboard_notify(int source) {
+  struct Clipboard_Notify *node;
+
+  node = clip_notify_list;
+  while (node != NULL) {
+    node->handler(source, node->data);
+    node = node->next;
+  }
+}
+
+////////////////////////////////////////////////////////////////
 // wait/run/check/ready:
 
 void (*Fl::idle)(); // see Fl::add_idle.cxx for the add/remove functions
@@ -880,6 +945,8 @@
       fl_oldfocus = p;
     }
     e_number = old_event;
+    // let the platform code do what it needs
+    fl_update_focus();
   }
 }
 
@@ -1361,7 +1428,10 @@
 ////////////////////////////////////////////////////////////////
 // hide() destroys the X window, it does not do unmap!
 
-#if !defined(WIN32) && USE_XFT
+#if defined(WIN32)
+extern void fl_clipboard_notify_untarget(HWND wnd);
+extern void fl_update_clipboard(void);
+#elif USE_XFT
 extern void fl_destroy_xft_draw(Window);
 #endif
 
@@ -1408,14 +1478,10 @@
 #if defined(WIN32)
   // this little trick keeps the current clipboard alive, even if we are about
   // to destroy the window that owns the selection.
-  if (GetClipboardOwner()==ip->xid) {
-    Fl_Window *w1 = Fl::first_window();
-    if (w1 && OpenClipboard(fl_xid(w1))) {
-      EmptyClipboard();
-      SetClipboardData(CF_TEXT, NULL);
-      CloseClipboard();
-    }
-  }
+  if (GetClipboardOwner()==ip->xid)
+    fl_update_clipboard();
+  // Make sure we unlink this window from the clipboard chain
+  fl_clipboard_notify_untarget(ip->xid);
   // Send a message to myself so that I'll get out of the event loop...
   PostMessage(ip->xid, WM_APP, 0, 0);
   if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc);
diff --git a/common/fltk/src/Fl_Image.cxx b/common/fltk/src/Fl_Image.cxx
index 4117ba7..58157be 100644
--- a/common/fltk/src/Fl_Image.cxx
+++ b/common/fltk/src/Fl_Image.cxx
@@ -172,6 +172,19 @@
 //
 // RGB image class...
 //
+
+int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg);
+
+/** The constructor creates a new RGBA image from the specified Fl_Pixmap. */
+Fl_RGB_Image::Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg):
+  Fl_Image(pxm->w(), pxm->h(), 4), id_(0), mask_(0)
+{
+  array = new uchar[w() * h() * d()];
+  alloc_array = 1;
+  fl_convert_pixmap(pxm->data(), (uchar*)array, bg);
+  data((const char **)&array, 1);
+}
+
 /**  The destructor free all memory and server resources that are used by  the image. */
 Fl_RGB_Image::~Fl_RGB_Image() {
   uncache();
diff --git a/common/fltk/src/Fl_Window.cxx b/common/fltk/src/Fl_Window.cxx
index 1aadb01..1ece624 100644
--- a/common/fltk/src/Fl_Window.cxx
+++ b/common/fltk/src/Fl_Window.cxx
@@ -59,14 +59,16 @@
   resizable(0);
   size_range_set = 0;
   minw = maxw = minh = maxh = 0;
+  no_fullscreen_x = 0;
+  no_fullscreen_y = 0;
+  no_fullscreen_w = w();
+  no_fullscreen_h = h();
   callback((Fl_Callback*)default_callback);
 }
 
 Fl_Window::Fl_Window(int X,int Y,int W, int H, const char *l)
 : Fl_Group(X, Y, W, H, l) {
   cursor_default = FL_CURSOR_DEFAULT;
-  cursor_fg      = FL_BLACK;
-  cursor_bg      = FL_WHITE;
 
   _Fl_Window();
   set_flag(FORCE_POSITION);
@@ -76,8 +78,6 @@
 // fix common user error of a missing end() with current(0):
   : Fl_Group((Fl_Group::current(0),0), 0, W, H, l) {
   cursor_default = FL_CURSOR_DEFAULT;
-  cursor_fg      = FL_BLACK;
-  cursor_bg      = FL_WHITE;
 
   _Fl_Window();
   clear_visible();
diff --git a/common/fltk/src/Fl_Window_fullscreen.cxx b/common/fltk/src/Fl_Window_fullscreen.cxx
index ea56343..9e62a9d 100644
--- a/common/fltk/src/Fl_Window_fullscreen.cxx
+++ b/common/fltk/src/Fl_Window_fullscreen.cxx
@@ -60,39 +60,48 @@
 #endif
 }
 
+void fullscreen_x(Fl_Window *w);
+void fullscreen_off_x();
+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H);
+
+/* Note: The previous implementation toggled border(). With this new
+   implementation this is not necessary. Additionally, if we do that,
+   the application may lose focus when switching out of fullscreen
+   mode with some window managers. Besides, the API does not say that
+   the FLTK border state should be toggled; it only says that the
+   borders should not be *visible*. 
+*/
 void Fl_Window::fullscreen() {
-#ifndef WIN32
-  //this would clobber the fake wm, since it relies on the border flags to
-  //determine its thickness
-  border(0);
-#endif
-#if defined(__APPLE__) || defined(WIN32) || defined(USE_X11)
-  int sx, sy, sw, sh;
-  Fl::screen_xywh(sx, sy, sw, sh, x(), y(), w(), h());
-  // if we are on the main screen, we will leave the system menu bar unobstructed
-  if (Fl::x()>=sx && Fl::y()>=sy && Fl::x()+Fl::w()<=sx+sw && Fl::y()+Fl::h()<=sy+sh) {
-    sx = Fl::x(); sy = Fl::y(); 
-    sw = Fl::w(); sh = Fl::h();
+  if (shown() && !(flags() & Fl_Widget::FULLSCREEN)) {
+    no_fullscreen_x = x();
+    no_fullscreen_y = y();
+    no_fullscreen_w = w();
+    no_fullscreen_h = h();
+    fullscreen_x(this);
+  } else {
+    set_flag(FULLSCREEN);
   }
-  if (x()==sx) x(sx+1); // make sure that we actually execute the resize
-#if defined(USE_X11)
-  resize(0, 0, w(), h()); // work around some quirks in X11
-#endif
-  resize(sx, sy, sw, sh);
-#else
-  if (!x()) x(1); // make sure that we actually execute the resize
-  resize(0,0,Fl::w(),Fl::h());
-#endif
 }
 
 void Fl_Window::fullscreen_off(int X,int Y,int W,int H) {
-  // this order produces less blinking on IRIX:
-  resize(X,Y,W,H);
-#ifndef WIN32
-  border(1);
-#endif
+  if (shown() && (flags() & Fl_Widget::FULLSCREEN)) {
+    fullscreen_off_x(this, X, Y, W, H);
+  } else {
+    clear_flag(FULLSCREEN);
+  }
+  no_fullscreen_x = no_fullscreen_y = no_fullscreen_w = no_fullscreen_h = 0;
 }
 
+void Fl_Window::fullscreen_off() {
+  if (!no_fullscreen_x && !no_fullscreen_y) {
+    // Window was initially created fullscreen - default to current monitor
+    no_fullscreen_x = x();
+    no_fullscreen_y = y();
+  }
+  fullscreen_off(no_fullscreen_x, no_fullscreen_y, no_fullscreen_w, no_fullscreen_h);
+}
+
+
 //
 // End of "$Id: Fl_Window_fullscreen.cxx 8515 2011-03-12 21:36:21Z manolo $".
 //
diff --git a/common/fltk/src/Fl_cocoa.mm b/common/fltk/src/Fl_cocoa.mm
index c113564..5fd52d6 100644
--- a/common/fltk/src/Fl_cocoa.mm
+++ b/common/fltk/src/Fl_cocoa.mm
@@ -61,6 +61,7 @@
 #include <stdarg.h>
 
 #import <Cocoa/Cocoa.h>
+#import <Carbon/Carbon.h>
 
 #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h
 #if defined(__LP64__) && __LP64__
@@ -107,7 +108,6 @@
 CGContextRef fl_gc = 0;
 void *fl_system_menu;                   // this is really a NSMenu*
 Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
-void *fl_default_cursor;		// this is really a NSCursor*
 void *fl_capture = 0;			// (NSWindow*) we need this to compensate for a missing(?) mouse capture
 bool fl_show_iconic;                    // true if called from iconize() - shows the next created window in collapsed state
 //int fl_disable_transient_for;           // secret method of removing TRANSIENT_FOR
@@ -124,6 +124,8 @@
 extern Fl_Window* fl_xmousewin;
 #endif
 
+bool use_simple_keyboard = false;
+
 enum { FLTKTimerEvent = 1, FLTKDataReadyEvent };
 
 
@@ -140,6 +142,39 @@
 {
 }
 
+// Undocumented voodoo. Taken from Mozilla.
+#define ENABLE_ROMAN_KYBDS_ONLY -23
+
+void fl_update_focus(void)
+{
+  Fl_Widget *focus;
+
+  focus = Fl::grab();
+  if (!focus)
+    focus = Fl::focus();
+  if (!focus)
+    return;
+
+  if (focus->simple_keyboard())
+    use_simple_keyboard = true;
+  else
+    use_simple_keyboard = false;
+
+  // Force a "Roman" or "ASCII" keyboard, which both the Mozilla and
+  // Safari people seem to think implies turning off advanced IME stuff
+  // (see nsTSMManager::SyncKeyScript in Mozilla and enableSecureTextInput
+  // in Safari/Webcore). Should be good enough for us then...
+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+  CFArrayRef inputSources = TISCreateASCIICapableInputSourceList();
+  TSMSetDocumentProperty(TSMGetActiveDocument(),
+                         kTSMDocumentEnabledInputSourcesPropertyTag,
+                         sizeof(CFArrayRef), &inputSources);
+  CFRelease(inputSources);
+#else
+  KeyScript(use_simple_keyboard ? ENABLE_ROMAN_KYBDS_ONLY : smKeyEnableKybds);
+#endif  
+}
+
 /*
  * Mac keyboard lookup table
  * See also the inverse converter vktab in Fl_get_key_mac.cxx
@@ -614,6 +649,10 @@
 {
   containsGLsubwindow = contains;
 }
+- (BOOL)canBecomeKeyWindow
+{
+  return YES;
+}
 @end
 
 @interface FLApplication : NSObject
@@ -843,6 +882,25 @@
 }
 @end
 
+static const char* cocoaDead2FLTK(const char *in)
+{
+  if (strcmp(in, "\140") == 0)      // GRAVE ACCENT
+    return "\314\200";              // COMBINING GRAVE ACCENT
+  if (strcmp(in, "\302\264") == 0)  // ACUTE ACCENT
+    return "\314\201";              // COMBINING ACUTE ACCENT
+  if (strcmp(in, "\136") == 0)      // CIRCUMFLEX ACCENT
+    return "\314\202";              // COMBINING CIRCUMFLEX ACCENT
+  if (strcmp(in, "\176") == 0)      // TILDE
+    return "\314\203";              // COMBINING TILDE
+  if (strcmp(in, "\302\250") == 0)  // DIAERESIS
+    return "\314\210";              // COMBINING DIAERESIS
+  // FIXME: OS X dead key behaviour isn't documented and I don't have
+  //        any more keyboards to test with...
+
+  // hope that OS X gave us something proper to begin with
+  return in;
+}
+
 /*
 Handle cocoa keyboard events
 Events during a character composition sequence:
@@ -1033,6 +1091,10 @@
   fl_lock_function();
   FLWindow *nsw = (FLWindow*)[notif object];
   Fl_Window *window = [nsw getFl_Window];
+  /* Fullscreen windows obscure all other windows so we need to return
+     to a "normal" level when the user switches to another window */
+  if (window->fullscreen_active())
+    [nsw setLevel:NSNormalWindowLevel];
   Fl::handle( FL_UNFOCUS, window);
   fl_unlock_function();
 }
@@ -1041,6 +1103,9 @@
   fl_lock_function();
   FLWindow *nsw = (FLWindow*)[notif object];
   Fl_Window *w = [nsw getFl_Window];
+  /* Restore previous fullscreen level */
+  if (w->fullscreen_active())
+    [nsw setLevel:NSStatusWindowLevel];
   if ( w->border() || (!w->modal() && !w->tooltip_window()) ) Fl::handle( FL_FOCUS, w);
   fl_unlock_function();
 }
@@ -1228,9 +1293,13 @@
 }
 @end
 
+static void clipboard_check(void);
+
 @implementation FLApplication
 + (void)sendEvent:(NSEvent *)theEvent
 {
+  // update clipboard status
+  clipboard_check();
   NSEventType type = [theEvent type];  
   if (type == NSLeftMouseDown) {
     fl_lock_function();
@@ -1285,8 +1354,6 @@
 					  dequeue:YES];
     while (ign_event);
     
-    fl_default_cursor = [NSCursor arrowCursor];
-
     // bring the application into foreground without a 'CARB' resource
     Boolean same_psn;
     ProcessSerialNumber cur_psn, front_psn;
@@ -1586,6 +1653,7 @@
 - (void)drawRect:(NSRect)rect;
 - (BOOL)acceptsFirstResponder;
 - (BOOL)acceptsFirstMouse:(NSEvent*)theEvent;
+- (void)resetCursorRects;
 - (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
 - (void)mouseUp:(NSEvent *)theEvent;
 - (void)rightMouseUp:(NSEvent *)theEvent;
@@ -1643,6 +1711,16 @@
   Fl_Window *first = Fl::first_window();
   return (first == w || !first->modal());
 }
+- (void)resetCursorRects {
+  Fl_Window *w = [(FLWindow*)[self window] getFl_Window];
+  Fl_X *i = Fl_X::i(w);
+  // We have to have at least one cursor rect for invalidateCursorRectsForView
+  // to work, hence the "else" clause.
+  if (i->cursor)
+    [self addCursorRect:[self visibleRect] cursor:(NSCursor*)i->cursor];
+  else
+    [self addCursorRect:[self visibleRect] cursor:[NSCursor arrowCursor]];
+}
 - (void)mouseUp:(NSEvent *)theEvent {
   cocoaMouseHandler(theEvent);
 }
@@ -1702,8 +1780,13 @@
       break;
     }
   }
+  // Don't send cmd-<key> to interpretKeyEvents because it beeps.
   if (!no_text_key && !(Fl::e_state & FL_META) ) {
-    // Don't send cmd-<key> to interpretKeyEvents because it beeps.
+    // The simple keyboard model will ignore insertText, so we need to grab
+    // the symbol directly from the event. Note that we still use setMarkedText.
+    if (use_simple_keyboard)
+      [FLView prepareEtext:[theEvent charactersIgnoringModifiers]];
+
     // Then we can let the OS have a stab at it and see if it thinks it
     // should result in some text
     NSText *edit = [[theEvent window]  fieldEditor:YES forObject:nil];
@@ -1882,21 +1965,30 @@
   //NSLog(@"insertText: received=%@",received);
 
   if (!in_key_event) fl_lock_function();
+
+  // Simple keyboard widgets do not want these side channel inputs.
+  if (use_simple_keyboard)
+    goto end;
+
   [FLView prepareEtext:received];
+
   // We can get called outside of key events (e.g. from the character
-  // palette). Transform such actions to FL_PASTE events.
+  // palette). We need to fake our own key event at that point.
   if (!in_key_event) {
     Fl_Window *target = [(FLWindow*)[self window] getFl_Window];
-    Fl::handle(FL_PASTE, target);
+    Fl::e_keysym = Fl::e_original_keysym = 0;
+    Fl::handle(FL_KEYDOWN, target);
     // for some reason, the window does not redraw until the next mouse move or button push
     // sending a 'redraw()' or 'awake()' does not solve the issue!
     Fl::flush();
   }
+
+end:
   if (!in_key_event) fl_unlock_function();
 }
 
 - (void)setMarkedText:(id)aString selectedRange:(NSRange)newSelection  {
-  NSString *received;
+  NSString *received, *current, *aggregate;
   if (newSelection.location == 0) {
     [self unmarkText];
     return;
@@ -1907,11 +1999,47 @@
     received = (NSString*)aString;
   }
   //NSLog(@"setMarkedText: %@ %d %d",received,newSelection.location,newSelection.length);
+
+  fl_lock_function();
+
+  // Simple keyboard widgets generally do not want these side channel
+  // inputs, but we have no other way of getting dead keys so we make
+  // an exception in that case.
+  if (use_simple_keyboard) {
+    if (in_key_event && (Fl::e_length == 0)) {
+      [FLView prepareEtext:received];
+
+      Fl::e_text = (char*)cocoaDead2FLTK(Fl::e_text);
+      Fl::e_length = strlen(Fl::e_text);
+    }
+    goto end;
+  }
+
   // This code creates the OS X behaviour of seeing dead keys as things
   // are being composed.
+  //
+  // Note: The concatenation thing is because of how OS X deals with
+  //       invalid sequences. At that point it will spit out one call
+  //       to insertText with the now aborted sequence, and one new
+  //       call to setMarkedText with the new sequence. Since we want
+  //       both to be visible, we need to concatenate.
   next_compose_length = newSelection.location;
-  [FLView prepareEtext:received];
-  //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", received, Fl::e_length, next_compose_length);
+  current = [NSString stringWithUTF8String:Fl::e_text];
+  aggregate = [current stringByAppendingString:received];
+
+  [FLView prepareEtext:aggregate];
+  //NSLog(@"Fl::e_text=%@ Fl::e_length=%d next_compose_length=%d", aggregate, Fl::e_length, next_compose_length);
+
+  // We can get called outside of key events (e.g. from the character
+  // palette). We need to fake our own key event at that point.
+  if (!in_key_event) {
+    Fl_Window *target = [(FLWindow*)[self window] getFl_Window];
+    Fl::e_keysym = Fl::e_original_keysym = 0;
+    Fl::handle(FL_KEYDOWN, target);
+  }
+
+end:
+  fl_unlock_function();
 }
 
 - (void)unmarkText {
@@ -1981,6 +2109,22 @@
 
 @end
 
+void fullscreen_x(Fl_Window *w) {
+  w->_set_fullscreen();
+  /* On OS X < 10.6, it is necessary to recreate the window. This is done
+     with hide+show. */
+  w->hide();
+  w->show();
+  Fl::handle(FL_FULLSCREEN, w);
+}
+
+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) {
+  w->_clear_fullscreen();
+  w->hide();
+  w->resize(X, Y, W, H);
+  w->show();
+  Fl::handle(FL_FULLSCREEN, w);
+}
 
 /*
  * go ahead, create that (sub)window
@@ -1996,7 +2140,7 @@
     x->other_xid = 0;
     x->region = 0;
     x->subRegion = 0;
-    x->cursor = fl_default_cursor;
+    x->cursor = NULL;
     x->gc = 0;			// stay 0 for Quickdraw; fill with CGContext for Quartz
     Fl_Window *win = w->window();
     Fl_X *xo = Fl_X::i(win);
@@ -2098,12 +2242,19 @@
     x->other_xid = 0; // room for doublebuffering image map. On OS X this is only used by overlay windows
     x->region = 0;
     x->subRegion = 0;
-    x->cursor = fl_default_cursor;
+    x->cursor = NULL;
     x->xidChildren = 0;
     x->xidNext = 0;
     x->gc = 0;
 	  
     NSRect srect = [[NSScreen mainScreen] frame];
+    if (w->flags() & Fl_Widget::FULLSCREEN) {
+      int sx, sy, sw, sh;
+      Fl::screen_xywh(sx, sy, sw, sh, w->x(), w->y(), w->w(), w->h());
+      w->resize(sx, sy, sw, sh);
+      winstyle = NSBorderlessWindowMask;
+      winlevel = NSStatusWindowLevel;
+    }
     NSRect crect;
     crect.origin.x = w->x(); 
     crect.origin.y = srect.size.height - (w->y() + w->h());
@@ -2552,6 +2703,27 @@
   receiver.handle(FL_PASTE);
 }
 
+extern void fl_trigger_clipboard_notify(int source);
+
+void fl_clipboard_notify_change() {
+  // No need to do anything here...
+}
+
+static void clipboard_check(void)
+{
+  PasteboardSyncFlags flags;
+
+  allocatePasteboard();
+  flags = PasteboardSynchronize(myPasteboard);
+
+  if (!(flags & kPasteboardModified))
+    return;
+  if (flags & kPasteboardClientIsOwner)
+    return;
+
+  fl_trigger_clipboard_notify(1);
+}
+
 void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
 {
   // check, if this timer slot exists already
@@ -2676,6 +2848,10 @@
     [[(NSWindow *)xid contentView] release];
     [(NSWindow *)xid close];
   }
+  if (cursor) {
+    [(NSCursor*)cursor release];
+    cursor = NULL;
+  }
 }
 
 void Fl_X::map() {
@@ -2791,68 +2967,106 @@
   return [image autorelease];
 }
 
-static NSCursor *PrepareCursor(NSCursor *cursor, CGContextRef (*f)() )
+int Fl_X::set_cursor(Fl_Cursor c)
 {
-  if (cursor == nil) {
-    CGContextRef c = f();
-    NSImage *image = CGBitmapContextToNSImage(c);
-    fl_delete_offscreen( (Fl_Offscreen)c ); 
-    NSPoint pt = {[image size].width/2, [image size].height/2};
-    cursor = [[NSCursor alloc] initWithImage:image hotSpot:pt];
+  if (cursor) {
+    [(NSCursor*)cursor release];
+    cursor = NULL;
   }
-  return cursor;
+
+  switch (c) {
+  case FL_CURSOR_ARROW:   cursor = [NSCursor arrowCursor]; break;
+  case FL_CURSOR_CROSS:   cursor = [NSCursor crosshairCursor]; break;
+  case FL_CURSOR_INSERT:  cursor = [NSCursor IBeamCursor]; break;
+  case FL_CURSOR_HAND:    cursor = [NSCursor pointingHandCursor]; break;
+  case FL_CURSOR_MOVE:    cursor = [NSCursor openHandCursor]; break;
+  case FL_CURSOR_NS:      cursor = [NSCursor resizeUpDownCursor]; break;
+  case FL_CURSOR_WE:      cursor = [NSCursor resizeLeftRightCursor]; break;
+  case FL_CURSOR_N:       cursor = [NSCursor resizeUpCursor]; break;
+  case FL_CURSOR_E:       cursor = [NSCursor resizeRightCursor]; break;
+  case FL_CURSOR_W:       cursor = [NSCursor resizeLeftCursor]; break;
+  case FL_CURSOR_S:       cursor = [NSCursor resizeDownCursor]; break;
+  default:
+    return 0;
+  }
+
+  [(NSCursor*)cursor retain];
+
+  [(NSWindow*)xid invalidateCursorRectsForView:[(NSWindow*)xid contentView]];
+
+  return 1;
 }
 
-void Fl_X::set_cursor(Fl_Cursor c)
-{
-  NSCursor *icrsr;
-  switch (c) {
-    case FL_CURSOR_CROSS:  icrsr = [NSCursor crosshairCursor]; break;
-    case FL_CURSOR_WAIT:
-      static NSCursor *watch = nil;
-      watch = PrepareCursor(watch,  &Fl_X::watch_cursor_image);
-      icrsr = watch;
-      break;
-    case FL_CURSOR_INSERT: icrsr = [NSCursor IBeamCursor]; break;
-    case FL_CURSOR_N:      icrsr = [NSCursor resizeUpCursor]; break;
-    case FL_CURSOR_S:      icrsr = [NSCursor resizeDownCursor]; break;
-    case FL_CURSOR_NS:     icrsr = [NSCursor resizeUpDownCursor]; break;
-    case FL_CURSOR_HELP:   
-      static NSCursor *help = nil;
-      help = PrepareCursor(help,  &Fl_X::help_cursor_image);
-      icrsr = help;
-      break;
-    case FL_CURSOR_HAND:   icrsr = [NSCursor pointingHandCursor]; break;
-    case FL_CURSOR_MOVE:   icrsr = [NSCursor openHandCursor]; break;
-    case FL_CURSOR_NE:
-    case FL_CURSOR_SW:
-    case FL_CURSOR_NESW:   
-      static NSCursor *nesw = nil;
-      nesw = PrepareCursor(nesw,  &Fl_X::nesw_cursor_image);
-      icrsr = nesw;
-      break;
-    case FL_CURSOR_E:      icrsr = [NSCursor resizeRightCursor]; break;
-    case FL_CURSOR_W:      icrsr = [NSCursor resizeLeftCursor]; break;
-    case FL_CURSOR_WE:     icrsr = [NSCursor resizeLeftRightCursor]; break;
-    case FL_CURSOR_SE:
-    case FL_CURSOR_NW:
-    case FL_CURSOR_NWSE:   
-      static NSCursor *nwse = nil;
-      nwse = PrepareCursor(nwse,  &Fl_X::nwse_cursor_image);
-      icrsr = nwse;
-      break;
-    case FL_CURSOR_NONE:   
-      static NSCursor *none = nil;
-      none = PrepareCursor(none,  &Fl_X::none_cursor_image);
-      icrsr = none; 
-      break;
-    case FL_CURSOR_ARROW:
-    case FL_CURSOR_DEFAULT:
-    default:			   icrsr = [NSCursor arrowCursor];
-      break;
+int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
+  if (cursor) {
+    [(NSCursor*)cursor release];
+    cursor = NULL;
   }
-  [icrsr set];
-  cursor = icrsr;
+
+  if ((hotx < 0) || (hotx >= image->w()))
+    return 0;
+  if ((hoty < 0) || (hoty >= image->h()))
+    return 0;
+
+  // OS X >= 10.6 can create a NSImage from a CGImage, but we need to
+  // support older versions, hence this pesky handling.
+
+  NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc]
+                              initWithBitmapDataPlanes:NULL
+                              pixelsWide:image->w()
+                              pixelsHigh:image->h()
+                              bitsPerSample:8
+                              samplesPerPixel:image->d()
+                              hasAlpha:!(image->d() & 1)
+                              isPlanar:NO
+                              colorSpaceName:(image->d()<=2) ? NSDeviceWhiteColorSpace : NSDeviceRGBColorSpace
+                              bytesPerRow:(image->w() * image->d())
+                              bitsPerPixel:(image->d()*8)];
+
+  // Alpha needs to be premultiplied for this format
+
+  const uchar *i = (const uchar*)*image->data();
+  unsigned char *o = [bitmap bitmapData];
+  for (int y = 0;y < image->h();y++) {
+    if (image->d() & 1) {
+      for (int x = 0;x < image->w();x++) {
+        unsigned int alpha;
+        if (image->d() == 4) {
+          alpha = i[3];
+          *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255);
+          *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255);
+        }
+
+        alpha = i[1];
+        *o++ = (unsigned char)((unsigned int)*i++ * alpha / 255);
+        *o++ = alpha;
+        i++;
+      }
+    } else {
+      // No alpha, so we can just copy everything directly.
+      int len = image->w() * image->d();
+      memcpy(o, i, len);
+      o += len;
+      i += len;
+    }
+    i += image->ld();
+  }
+
+  NSImage *nsimage = [[NSImage alloc]
+                      initWithSize:NSMakeSize(image->w(), image->h())];
+
+  [nsimage addRepresentation:bitmap];
+
+  cursor = [[NSCursor alloc]
+            initWithImage:nsimage
+            hotSpot:NSMakePoint(hotx, hoty)];
+
+  [(NSWindow*)xid invalidateCursorRectsForView:[(NSWindow*)xid contentView]];
+
+  [bitmap release];
+  [nsimage release];
+
+  return 1;
 }
 
 @interface FLaboutItemTarget : NSObject 
diff --git a/common/fltk/src/Fl_grab.cxx b/common/fltk/src/Fl_grab.cxx
index 76c9e9e..38724bd 100644
--- a/common/fltk/src/Fl_grab.cxx
+++ b/common/fltk/src/Fl_grab.cxx
@@ -38,6 +38,7 @@
 // override_redirect, it does similar things on WIN32.
 
 extern void fl_fix_focus(); // in Fl.cxx
+void fl_update_focus(void);
 
 #ifdef WIN32
 // We have to keep track of whether we have captured the mouse, since
@@ -50,7 +51,19 @@
 extern void *fl_capture;
 #endif
 
+#if !(defined(WIN32) || defined(__APPLE__))
+extern int ewmh_supported(); // from Fl_x.cxx
+#endif
+
 void Fl::grab(Fl_Window* win) {
+    Fl_Window *fullscreen_win = NULL;
+    for (Fl_Window *W = Fl::first_window(); W; W = Fl::next_window(W)) {
+      if (W->fullscreen_active()) {
+        fullscreen_win = W;
+        break;
+      }
+    }
+
   if (win) {
     if (!grab_) {
 #ifdef WIN32
@@ -60,8 +73,9 @@
       fl_capture = Fl_X::i(first_window())->xid;
       Fl_X::i(first_window())->set_key_window();
 #else
+      Window xid = fullscreen_win ? fl_xid(fullscreen_win) : fl_xid(first_window());
       XGrabPointer(fl_display,
-		   fl_xid(first_window()),
+		   xid,
 		   1,
 		   ButtonPressMask|ButtonReleaseMask|
 		   ButtonMotionMask|PointerMotionMask,
@@ -71,7 +85,7 @@
 		   0,
 		   fl_event_time);
       XGrabKeyboard(fl_display,
-		    fl_xid(first_window()),
+		    xid,
 		    1,
 		    GrabModeAsync,
 		    GrabModeAsync, 
@@ -79,6 +93,7 @@
 #endif
     }
     grab_ = win;
+    fl_update_focus();
   } else {
     if (grab_) {
 #ifdef WIN32
@@ -87,13 +102,17 @@
 #elif defined(__APPLE__)
       fl_capture = 0;
 #else
+      // We must keep the grab in the non-EWMH fullscreen case
+      if (!fullscreen_win || ewmh_supported()) {
       XUngrabKeyboard(fl_display, fl_event_time);
+      }
       XUngrabPointer(fl_display, fl_event_time);
       // this flush is done in case the picked menu item goes into
       // an infinite loop, so we don't leave the X server locked up:
       XFlush(fl_display);
 #endif
       grab_ = 0;
+      fl_update_focus();
       fl_fix_focus();
     }
   }
diff --git a/common/fltk/src/Fl_win32.cxx b/common/fltk/src/Fl_win32.cxx
index 54d9c81..d4ada8b 100644
--- a/common/fltk/src/Fl_win32.cxx
+++ b/common/fltk/src/Fl_win32.cxx
@@ -98,6 +98,8 @@
 Fl_Surface_Device* Fl_Surface_Device::_surface = (Fl_Surface_Device*)&fl_gdi_display; // the current target surface of graphics operations
 Fl_Display_Device *Fl_Display_Device::_display = &fl_gdi_display; // the platform display
 
+bool use_simple_keyboard = false;
+
 // dynamic wsock dll handling api:
 #if defined(__CYGWIN__) && !defined(SOCKET)
 # define SOCKET int
@@ -131,6 +133,8 @@
  * size and link dependencies.
  */
 static HMODULE s_imm_module = 0;
+typedef BOOL (WINAPI* flTypeImmAssociateContextEx)(HWND, HIMC, DWORD);
+static flTypeImmAssociateContextEx flImmAssociateContextEx = 0;
 typedef HIMC (WINAPI* flTypeImmGetContext)(HWND);
 static flTypeImmGetContext flImmGetContext = 0;
 typedef BOOL (WINAPI* flTypeImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
@@ -146,6 +150,7 @@
     if (!s_imm_module)
       Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n"
         "Please check your input method manager library accessibility.");
+    flImmAssociateContextEx = (flTypeImmAssociateContextEx)GetProcAddress(s_imm_module, "ImmAssociateContextEx");
     flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext");
     flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow");
     flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext");
@@ -424,7 +429,12 @@
         }
       }
 
-      TranslateMessage(&fl_msg);
+      // Don't bother with key to character translation as we do
+      // it manually for simpley keyboard widgets. In fact, calling
+      // TranslateMessage() just makes it more difficult as it sets
+      // a bunch of internal state.
+      if (!use_simple_keyboard)
+        TranslateMessage(&fl_msg);
       DispatchMessageW(&fl_msg);
       have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE);
     }
@@ -542,6 +552,36 @@
   const char* GetValue() const { return(out); }
 };
 
+void fl_update_clipboard(void) {
+  HWND hwnd = fl_xid(Fl::first_window());
+
+  if (!hwnd)
+    return;
+
+  if (!OpenClipboard(hwnd))
+    return;
+
+  EmptyClipboard();
+
+  int utf16_len = fl_utf8toUtf16(fl_selection_buffer[1],
+                                 fl_selection_length[1], 0, 0);
+
+  HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc.
+  LPVOID memLock = GlobalLock(hMem);
+
+  fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1],
+                 (unsigned short*) memLock, utf16_len + 1);
+
+  GlobalUnlock(hMem);
+  SetClipboardData(CF_UNICODETEXT, hMem);
+
+  CloseClipboard();
+
+  // In case Windows managed to lob of a WM_DESTROYCLIPBOARD during
+  // the above.
+  fl_i_own_selection[1] = 1;
+}
+
 // call this when you create a selection:
 void Fl::copy(const char *stuff, int len, int clipboard) {
   if (!stuff || len<0) return;
@@ -559,25 +599,9 @@
   memcpy(fl_selection_buffer[clipboard], stuff, len);
   fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
   fl_selection_length[clipboard] = len;
-  if (clipboard) {
-    // set up for "delayed rendering":
-    if (OpenClipboard(NULL)) {
-      // if the system clipboard works, use it
-      int utf16_len = fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], 0, 0);
-      EmptyClipboard();
-      HGLOBAL hMem = GlobalAlloc(GHND, utf16_len * 2 + 2); // moveable and zero'ed mem alloc.
-      LPVOID memLock = GlobalLock(hMem);
-      fl_utf8toUtf16(fl_selection_buffer[clipboard], fl_selection_length[clipboard], (unsigned short*) memLock, utf16_len + 1);
-      GlobalUnlock(hMem);
-      SetClipboardData(CF_UNICODETEXT, hMem);
-      CloseClipboard();
-      GlobalFree(hMem);
-      fl_i_own_selection[clipboard] = 0;
-    } else {
-      // only if it fails, instruct paste() to use the internal buffers
-      fl_i_own_selection[clipboard] = 1;
-    }
-  }
+  fl_i_own_selection[clipboard] = 1;
+  if (clipboard)
+    fl_update_clipboard();
 }
 
 // Call this when a "paste" operation happens:
@@ -630,6 +654,38 @@
   }
 }
 
+static HWND clipboard_wnd = 0;
+static HWND next_clipboard_wnd = 0;
+
+static bool initial_clipboard = true;
+
+void fl_clipboard_notify_change() {
+  // No need to do anything here...
+}
+
+void fl_clipboard_notify_target(HWND wnd) {
+  if (clipboard_wnd)
+    return;
+
+  // We get one fake WM_DRAWCLIPBOARD immediately, which we therefore
+  // need to ignore.
+  initial_clipboard = true;
+
+  clipboard_wnd = wnd;
+  next_clipboard_wnd = SetClipboardViewer(wnd);
+}
+
+void fl_clipboard_notify_untarget(HWND wnd) {
+  if (wnd != clipboard_wnd)
+    return;
+
+  ChangeClipboardChain(wnd, next_clipboard_wnd);
+  clipboard_wnd = next_clipboard_wnd = 0;
+
+  if (Fl::first_window())
+    fl_clipboard_notify_target(fl_xid(Fl::first_window()));
+}
+
 ////////////////////////////////////////////////////////////////
 char fl_is_ime = 0;
 void fl_get_codepage()
@@ -649,6 +705,49 @@
   }
 }
 
+void fl_update_focus(void)
+{
+  Fl_Widget *focus;
+  Fl_Window *win;
+
+  get_imm_module();
+
+  focus = Fl::grab();
+  if (!focus)
+    focus = Fl::focus();
+  if (!focus)
+    return;
+
+  // Grabs are special in that events are sent to the first
+  // available window
+  if (focus == Fl::grab())
+    win = Fl::first_window();
+  else {
+    win = focus->as_window();
+    if (!win)
+      win = focus->window();
+  }
+
+  if (!win) {
+    Fl::warning("Cannot find window for widget receiving focus");
+    return;
+  }
+
+  // No Win32 window created yet
+  if (!Fl_X::i(win) || !fl_xid(win))
+    return;
+
+  if (focus->simple_keyboard()) {
+    use_simple_keyboard = true;
+    if (flImmGetContext(fl_xid(win)) != 0)
+      flImmAssociateContextEx(fl_xid(win), 0, 0);
+  } else {
+    use_simple_keyboard = false;
+    if (flImmGetContext(fl_xid(win)) == 0)
+      flImmAssociateContextEx(fl_xid(win), 0, IACE_DEFAULT);
+  }
+}
+
 HWND fl_capture;
 
 static int mouse_event(Fl_Window *window, int what, int button,
@@ -796,6 +895,27 @@
   return extended ? extendedlut[vk] : vklut[vk];
 }
 
+static xchar msdead2fltk(xchar in)
+{
+  switch (in) {
+  case 0x0060:      // GRAVE ACCENT
+    return 0x0300;  // COMBINING GRAVE ACCENT
+  case 0x00b4:      // ACUTE ACCENT
+    return 0x0301;  // COMBINING ACUTE ACCENT
+  case 0x005e:      // CIRCUMFLEX ACCENT
+    return 0x0302;  // COMBINING CIRCUMFLEX ACCENT
+  case 0x007e:      // TILDE
+    return 0x0303;  // COMBINING TILDE
+  case 0x00a8:      // DIAERESIS
+    return 0x0308;  // COMBINING DIAERESIS
+  // FIXME: Windows dead key behaviour isn't documented and I don't have
+  //        any more keyboards to test with...
+  }
+
+  // hope that Windows gave us something proper to begin with
+  return in;
+}
+
 #if USE_COLORMAP
 extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx
 #endif
@@ -857,6 +977,8 @@
   //fl_msg.pt = ???
   //fl_msg.lPrivate = ???
 
+  MSG fl_orig_msg = fl_msg;
+
   Fl_Window *window = fl_find(hWnd);
 
   if (window) switch (uMsg) {
@@ -1036,23 +1158,82 @@
     if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK;
     Fl::e_state = state;
     static char buffer[1024];
-    if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
 
+    if (use_simple_keyboard) {
+      BYTE keystate[256];
+      WCHAR wbuf[8];
+      int ret;
+
+      // I'm not sure if we ever get WM_CHAR (& friends) without an initial
+      // WM_KEYDOWN (& friends), but if we do then we should not send such
+      // side band events to simple keyboard widgets.
+      if ((fl_orig_msg.message != WM_KEYDOWN) &&
+          (fl_orig_msg.message != WM_SYSKEYDOWN) &&
+          (fl_orig_msg.message != WM_KEYUP) &&
+          (fl_orig_msg.message != WM_SYSKEYUP))
+        break;
+
+      GetKeyboardState(keystate);
+
+      // Pressing Ctrl wreaks havoc with the symbol lookup, so turn that off.
+      // But AltGr shows up as Ctrl+Alt in Windows, so keep Ctrl if Alt is
+      // active.
+      if (!(keystate[VK_MENU] & (1<<31)))
+        keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0;
+
+      // We cannot inspect or modify Windows' internal state of the keyboard
+      // so we have to try to infer information from ToUnicode() and wedge
+      // things into a known state.
+      for (int i = 0;i < 2;i++) {
+        ret = ToUnicode(fl_orig_msg.wParam, 0, keystate, wbuf,
+                        sizeof(wbuf)/sizeof(wbuf[0]), 0);
+
+        // No symbol for this key (or unexpected length)
+        if ((ret == 0) || (ret < -1)) {
+          buffer[0] = 0;
+          Fl::e_length = 0;
+          break;
+        }
+
+        // A dead key. Convert this to a Unicode combining character so
+        // that the application can tell the difference between dead and
+        // normal keys.
+        if (ret == -1) {
+          xchar u = (xchar) msdead2fltk(wbuf[0]);
+          Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
+          buffer[Fl::e_length] = 0;
+          break;
+        }
+
+        // If we have two characters (or more) from ToUnicode(), that's
+        // an invalid sequence. One character chould mean a proper symbol,
+        // or it could mean a composed one. In both cases we need to call
+        // ToUnicode() again to get something sane.
+        if (i == 0)
+          continue;
+
+        // We should now have something sane. Give whatever we have to the
+        // application.
+        Fl::e_length = fl_utf8fromwc(buffer, 1024, wbuf, ret);
+        buffer[Fl::e_length] = 0;
+      }
+    } else if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) {
       xchar u = (xchar) wParam;
 //    Fl::e_length = fl_unicode2utf(&u, 1, buffer);
       Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
       buffer[Fl::e_length] = 0;
+    } else {
+      buffer[0] = 0;
+      Fl::e_length = 0;
+    }
 
-
-    } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
-      if (state & FL_NUM_LOCK) {
-        // Convert to regular keypress...
-	buffer[0] = Fl::e_keysym-FL_KP;
-	Fl::e_length = 1;
-      } else {
-        // Convert to special keypress...
-	buffer[0] = 0;
-	Fl::e_length = 0;
+    // The keypad area is a bit odd in that we need to change the keysym
+    // to properly indicate what the user meant, unlike other keys where
+    // we normally change the text and keep keysym stable.
+    if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) {
+      // The initial mapping tables give us a keysym that corresponds to
+      // numlock being on, so we only do something when it is off.
+      if (!(state & FL_NUM_LOCK)) {
 	switch (Fl::e_keysym) {
 	  case FL_KP + '0' :
 	    Fl::e_keysym = FL_Insert;
@@ -1084,30 +1265,10 @@
 	  case FL_KP + '.' :
 	    Fl::e_keysym = FL_Delete;
 	    break;
-	  case FL_KP + '/' :
-	  case FL_KP + '*' :
-	  case FL_KP + '-' :
-	  case FL_KP + '+' :
-	    buffer[0] = Fl::e_keysym-FL_KP;
-	    Fl::e_length = 1;
-	    break;
 	}
       }
-    } else if ((lParam & (1<<31))==0) {
-#ifdef FLTK_PREVIEW_DEAD_KEYS
-      if ((lParam & (1<<24))==0) { // clear if dead key (always?)
-        xchar u = (xchar) wParam;
-        Fl::e_length = fl_utf8fromwc(buffer, 1024, &u, 1);
-        buffer[Fl::e_length] = 0;
-      } else { // set if "extended key" (never printable?)
-        buffer[0] = 0;
-        Fl::e_length = 0;
-      }
-#else
-      buffer[0] = 0;
-      Fl::e_length = 0;
-#endif
     }
+
     Fl::e_text = buffer;
     if (lParam & (1<<31)) { // key up events.
       if (Fl::handle(FL_KEYUP, window)) return 0;
@@ -1125,12 +1286,28 @@
   case WM_MOUSEWHEEL: {
     static int delta = 0; // running total of all motion
     delta += (SHORT)(HIWORD(wParam));
+    Fl::e_dx = 0;
     Fl::e_dy = -delta / WHEEL_DELTA;
     delta += Fl::e_dy * WHEEL_DELTA;
     if (Fl::e_dy) Fl::handle(FL_MOUSEWHEEL, window);
     return 0;
   }
 
+// This is only defined on Vista and upwards...
+#ifndef WM_MOUSEHWHEEL
+#define WM_MOUSEHWHEEL 0x020E
+#endif
+
+  case WM_MOUSEHWHEEL: {
+    static int delta = 0; // running total of all motion
+    delta += (SHORT)(HIWORD(wParam));
+    Fl::e_dy = 0;
+    Fl::e_dx = delta / WHEEL_DELTA;
+    delta -= Fl::e_dx * WHEEL_DELTA;
+    if (Fl::e_dx) Fl::handle(FL_MOUSEWHEEL, window);
+    return 0;
+  }
+
   case WM_GETMINMAXINFO:
     Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam);
     break;
@@ -1185,33 +1362,26 @@
     fl_i_own_selection[1] = 0;
     return 1;
 
-  case WM_RENDERALLFORMATS:
-    fl_i_own_selection[1] = 0;
-    // Windoze seems unhappy unless I do these two steps. Documentation
-    // seems to vary on whether opening the clipboard is necessary or
-    // is in fact wrong:
-    CloseClipboard();
-    OpenClipboard(NULL);
-    // fall through...
-  case WM_RENDERFORMAT: {
-    HANDLE h;
-
-//  int l = fl_utf_nb_char((unsigned char*)fl_selection_buffer[1], fl_selection_length[1]);
-    int l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], NULL, 0); // Pass NULL buffer to query length required
-    h = GlobalAlloc(GHND, (l+1) * sizeof(unsigned short));
-    if (h) {
-      unsigned short *g = (unsigned short*) GlobalLock(h);
-//    fl_utf2unicode((unsigned char *)fl_selection_buffer[1], fl_selection_length[1], (xchar*)g);
-      l = fl_utf8toUtf16(fl_selection_buffer[1], fl_selection_length[1], g, (l+1));
-      g[l] = 0;
-      GlobalUnlock(h);
-      SetClipboardData(CF_UNICODETEXT, h);
+  case WM_CHANGECBCHAIN:
+    if ((hWnd == clipboard_wnd) &&
+        (next_clipboard_wnd == (HWND)wParam)) {
+      next_clipboard_wnd = (HWND)lParam;
+      return 0;
     }
+    break;
 
-    // Windoze also seems unhappy if I don't do this. Documentation very
-    // unclear on what is correct:
-    if (fl_msg.message == WM_RENDERALLFORMATS) CloseClipboard();
-    return 1;}
+  case WM_DRAWCLIPBOARD:
+    // When the clipboard moves between two FLTK windows,
+    // fl_i_own_selection will temporarily be false as we are
+    // processing this message. Hence the need to use fl_find().
+    if (!initial_clipboard && !fl_find(GetClipboardOwner()))
+      fl_trigger_clipboard_notify(1);
+    initial_clipboard = false;
+
+    if (next_clipboard_wnd)
+      SendMessage(next_clipboard_wnd, WM_DRAWCLIPBOARD, wParam, lParam);
+
+    return 0;
 
   default:
     if (Fl::handle(0,0)) return 0;
@@ -1320,6 +1490,11 @@
   X+=xoff;
   Y+=yoff;
 
+  if (w->flags() & Fl_Widget::FULLSCREEN) {
+    X = Y = 0;
+    bx = by = bt = 0;
+  }
+
   return ret;
 }
 
@@ -1370,6 +1545,58 @@
   }
 }
 
+static void make_fullscreen(Fl_Window *w, Window xid, int X, int Y, int W, int H) {
+  int sx, sy, sw, sh;
+  Fl::screen_xywh(sx, sy, sw, sh, X, Y, W, H);
+  DWORD flags = GetWindowLong(xid, GWL_STYLE);
+  flags = flags & ~(WS_THICKFRAME|WS_CAPTION);
+  SetWindowLong(xid, GWL_STYLE, flags);
+  // SWP_NOSENDCHANGING is so that we can override size limits
+  SetWindowPos(xid, HWND_TOP, sx, sy, sw, sh, SWP_NOSENDCHANGING | SWP_FRAMECHANGED);
+}
+
+void fullscreen_x(Fl_Window *w) {
+  w->_set_fullscreen();
+  make_fullscreen(w, fl_xid(w), w->x(), w->y(), w->w(), w->h());
+  Fl::handle(FL_FULLSCREEN, w);
+}
+
+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) {
+  w->_clear_fullscreen();
+  DWORD style = GetWindowLong(fl_xid(w), GWL_STYLE);
+  // Remove the xid temporarily so that Fl_X::fake_X_wm() behaves like it
+  // does in Fl_X::make().
+  HWND xid = fl_xid(w);
+  Fl_X::i(w)->xid = NULL;
+  int x, y, bt, bx, by;
+  switch (Fl_X::fake_X_wm(w, x, y, bt, bx, by)) {
+  case 0: 
+    break;
+  case 1: 
+    style |= WS_CAPTION; 
+    break;
+  case 2: 
+    if (w->border()) {
+      style |= WS_THICKFRAME | WS_CAPTION; 
+    }
+    break;
+  }
+  Fl_X::i(w)->xid = xid;
+  // Adjust for decorations (but not if that puts the decorations
+  // outside the screen)
+  if ((X != w->x()) || (Y != w->y())) {
+    X -= bx;
+    Y -= by+bt;
+  }
+  W += bx*2;
+  H += by*2+bt;
+  SetWindowLong(fl_xid(w), GWL_STYLE, style);
+  SetWindowPos(fl_xid(w), 0, X, Y, W, H,
+               SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
+  Fl::handle(FL_FULLSCREEN, w);
+}
+
+
 ////////////////////////////////////////////////////////////////
 
 /*
@@ -1408,7 +1635,6 @@
 
 char fl_show_iconic;	// hack for Fl_Window::iconic()
 // int fl_background_pixel = -1; // color to use for background
-HCURSOR fl_default_cursor;
 UINT fl_wake_msg = 0;
 int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR
 
@@ -1456,7 +1682,7 @@
     if (!w->icon())
       w->icon((void *)LoadIcon(NULL, IDI_APPLICATION));
     wcw.hIcon = wcw.hIconSm = (HICON)w->icon();
-    wcw.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW);
+    wcw.hCursor = LoadCursor(NULL, IDC_ARROW);
     //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b);
     //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b));
     wcw.hbrBackground = NULL;
@@ -1499,18 +1725,26 @@
     int xwm = xp , ywm = yp , bt, bx, by;
     switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) {
       // No border (used for menus)
-      case 0: style |= WS_POPUP;
-              styleEx |= WS_EX_TOOLWINDOW;
+      case 0:
+        style |= WS_POPUP;
+        styleEx |= WS_EX_TOOLWINDOW;
 	      break;
 
       // Thin border and title bar
-      case 1: style |= WS_DLGFRAME | WS_CAPTION; break;
+      case 1:
+        style |= WS_DLGFRAME | WS_CAPTION;
+        if (!w->modal())
+          style |= WS_SYSMENU | WS_MINIMIZEBOX;
+        break;
 
       // Thick, resizable border and title bar, with maximize button
-      case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break;
+      case 2:
+        style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION;
+        if (!w->modal())
+          style |= WS_MINIMIZEBOX;
+        break;
     }
     if (by+bt) {
-      if (!w->modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX;
       wp += 2*bx;
       hp += 2*by+bt;
     }
@@ -1540,7 +1774,7 @@
   x->setwindow(w);
   x->region = 0;
   x->private_dc = 0;
-  x->cursor = fl_default_cursor;
+  x->cursor = LoadCursor(NULL, IDC_ARROW);
   if (!fl_codepage) fl_get_codepage();
 
   WCHAR *lab = NULL;
@@ -1566,9 +1800,23 @@
   );
   if (lab) free(lab);
 
+  if (w->flags() & Fl_Widget::FULLSCREEN) {
+  /* We need to make sure that the fullscreen is created on the
+     default monitor, ie the desktop where the shortcut is located
+     etc. This requires that CreateWindow is called with CW_USEDEFAULT
+     for x and y. We can then use GetWindowRect to determine which
+     monitor the window was placed on. */
+    RECT rect;
+    GetWindowRect(x->xid, &rect);
+    make_fullscreen(w, x->xid, rect.left, rect.top, 
+                    rect.right - rect.left, rect.bottom - rect.top);
+  }
+
   x->next = Fl_X::first;
   Fl_X::first = x;
 
+  fl_clipboard_notify_target(x->xid);
+
   x->wait_for_expose = 1;
   if (fl_show_iconic) {showit = 0; fl_show_iconic = 0;}
   if (showit) {
@@ -1581,7 +1829,7 @@
   // If we've captured the mouse, we dont want to activate any
   // other windows from the code, or we lose the capture.
   ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE :
-	     (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
+	     (Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL);
 
   // Register all windows for potential drag'n'drop operations
   fl_OleInitialize();
@@ -1777,6 +2025,129 @@
 }
 
 ////////////////////////////////////////////////////////////////
+
+#ifndef IDC_HAND
+#  define IDC_HAND  MAKEINTRESOURCE(32649)
+#endif // !IDC_HAND
+
+int Fl_X::set_cursor(Fl_Cursor c) {
+  LPSTR n;
+
+  if (c == FL_CURSOR_NONE)
+    cursor = NULL;
+  else {
+    switch (c) {
+    case FL_CURSOR_ARROW:   n = IDC_ARROW; break;
+    case FL_CURSOR_CROSS:   n = IDC_CROSS; break;
+    case FL_CURSOR_WAIT:    n = IDC_WAIT; break;
+    case FL_CURSOR_INSERT:  n = IDC_IBEAM; break;
+    case FL_CURSOR_HAND:    n = IDC_HAND; break;
+    case FL_CURSOR_HELP:    n = IDC_HELP; break;
+    case FL_CURSOR_MOVE:    n = IDC_SIZEALL; break;
+    case FL_CURSOR_N:
+    case FL_CURSOR_S:
+      // FIXME: Should probably have fallbacks for these instead
+    case FL_CURSOR_NS:      n = IDC_SIZENS; break;
+    case FL_CURSOR_NE:
+    case FL_CURSOR_SW:
+      // FIXME: Dito.
+    case FL_CURSOR_NESW:    n = IDC_SIZENESW; break;
+    case FL_CURSOR_E:
+    case FL_CURSOR_W:
+      // FIXME: Dito.
+    case FL_CURSOR_WE:      n = IDC_SIZEWE; break;
+    case FL_CURSOR_SE:
+    case FL_CURSOR_NW:
+      // FIXME: Dito.
+    case FL_CURSOR_NWSE:    n = IDC_SIZENWSE; break;
+    default:
+      return 0;
+    }
+
+    cursor = LoadCursor(NULL, n);
+    if (cursor == NULL)
+      return 0;
+  }
+
+  SetCursor(cursor);
+
+  return 1;
+}
+
+int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
+  BITMAPV5HEADER bi;
+  HBITMAP bitmap, mask;
+  DWORD *bits;
+
+  if ((hotx < 0) || (hotx >= image->w()))
+    return 0;
+  if ((hoty < 0) || (hoty >= image->h()))
+    return 0;
+
+  memset(&bi, 0, sizeof(BITMAPV5HEADER));
+
+  bi.bV5Size        = sizeof(BITMAPV5HEADER);
+  bi.bV5Width       = image->w();
+  bi.bV5Height      = image->h();
+  bi.bV5Planes      = 1;
+  bi.bV5BitCount    = 32;
+  bi.bV5Compression = BI_BITFIELDS;
+  bi.bV5RedMask     = 0x00FF0000;
+  bi.bV5GreenMask   = 0x0000FF00;
+  bi.bV5BlueMask    = 0x000000FF;
+  bi.bV5AlphaMask   = 0xFF000000;
+
+  HDC hdc;
+
+  hdc = GetDC(NULL);
+  bitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+  ReleaseDC(NULL, hdc);
+
+  const uchar *i = (const uchar*)*image->data();
+  for (int y = 0;y < image->h();y++) {
+    for (int x = 0;x < image->w();x++) {
+      switch (image->d()) {
+      case 1:
+        *bits = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
+        break;
+      case 2:
+        *bits = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
+        break;
+      case 3:
+        *bits = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
+        break;
+      case 4:
+        *bits = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
+        break;
+      }
+      i += image->d();
+      bits++;
+    }
+    i += image->ld();
+  }
+
+  // A mask bitmap is still needed even though it isn't used
+  mask = CreateBitmap(image->w(),image->h(),1,1,NULL);
+
+  ICONINFO ii;
+
+  ii.fIcon    = FALSE;
+  ii.xHotspot = hotx;
+  ii.yHotspot = hoty;
+  ii.hbmMask  = mask;
+  ii.hbmColor = bitmap;
+
+  cursor = CreateIconIndirect(&ii);
+
+  DeleteObject(bitmap);
+  DeleteObject(mask);
+
+  SetCursor(cursor);
+
+  return 1;
+}
+
+////////////////////////////////////////////////////////////////
 // Implement the virtual functions for the base Fl_Window class:
 
 // If the box is a filled rectangle, we can make the redisplay *look*
diff --git a/common/fltk/src/Fl_x.cxx b/common/fltk/src/Fl_x.cxx
index 4ef92b0..8c72dba 100644
--- a/common/fltk/src/Fl_x.cxx
+++ b/common/fltk/src/Fl_x.cxx
@@ -52,6 +52,15 @@
 #  include <X11/Xlocale.h>
 #  include <X11/Xlib.h>
 #  include <X11/keysym.h>
+#  include <X11/cursorfont.h>
+
+#  if HAVE_XCURSOR
+#    include <X11/Xcursor/Xcursor.h>
+#  endif
+
+#  ifdef HAVE_XFIXES
+#  include <X11/extensions/Xfixes.h>
+#  endif
 
 static Fl_Xlib_Graphics_Driver fl_xlib_driver;
 static Fl_Display_Device fl_xlib_display(&fl_xlib_driver);
@@ -300,14 +309,20 @@
 Colormap fl_colormap;
 XIM fl_xim_im = 0;
 XIC fl_xim_ic = 0;
+Window fl_xim_win = 0;
 char fl_is_over_the_spot = 0;
 static XRectangle status_area;
+static bool have_xfixes = false;
+static int xfixes_event_base = 0;
 
 static Atom WM_DELETE_WINDOW;
 static Atom WM_PROTOCOLS;
 static Atom fl_MOTIF_WM_HINTS;
 static Atom TARGETS;
 static Atom CLIPBOARD;
+static Atom TIMESTAMP;
+static Atom PRIMARY_TIMESTAMP;
+static Atom CLIPBOARD_TIMESTAMP;
 Atom fl_XdndAware;
 Atom fl_XdndSelection;
 Atom fl_XdndEnter;
@@ -328,6 +343,9 @@
 Atom fl_XaTextUriList;
 Atom fl_NET_WM_NAME;			// utf8 aware window label
 Atom fl_NET_WM_ICON_NAME;		// utf8 aware window icon name
+Atom fl_NET_SUPPORTING_WM_CHECK;
+Atom fl_NET_WM_STATE;
+Atom fl_NET_WM_STATE_FULLSCREEN;
 
 /*
   X defines 32-bit-entities to have a format value of max. 32,
@@ -581,6 +599,65 @@
   if(xim_styles) XFree(xim_styles);
 }
 
+void fl_xim_deactivate(void);
+
+void fl_xim_activate(Window xid)
+{
+  if (!fl_xim_im)
+    return;
+
+  // If the focused window has changed, then use the brute force method
+  // of completely recreating the input context.
+  if (fl_xim_win != xid) {
+    fl_xim_deactivate();
+
+    fl_new_ic();
+    fl_xim_win = xid;
+
+    XSetICValues(fl_xim_ic,
+                 XNFocusWindow, fl_xim_win,
+                 XNClientWindow, fl_xim_win,
+                 NULL);
+  }
+
+  fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
+}
+
+void fl_xim_deactivate(void)
+{
+  if (!fl_xim_ic)
+    return;
+
+  XDestroyIC(fl_xim_ic);
+  fl_xim_ic = NULL;
+
+  fl_xim_win = 0;
+}
+
+extern Fl_Window *fl_xfocus;
+
+void fl_update_focus(void)
+{
+  Fl_Widget *focus;
+
+  focus = Fl::grab();
+  if (!focus)
+    focus = Fl::focus();
+  if (!focus)
+    return;
+
+  if (focus->simple_keyboard()) {
+    fl_xim_deactivate();
+  } else {
+    // fl_xfocus should always be set if something has focus, but let's
+    // play it safe
+    if (!fl_xfocus || !fl_xid(fl_xfocus))
+      return;
+
+    fl_xim_activate(fl_xid(fl_xfocus));
+  }
+}
+
 void fl_open_display() {
   if (fl_display) return;
 
@@ -604,6 +681,9 @@
   fl_MOTIF_WM_HINTS     = XInternAtom(d, "_MOTIF_WM_HINTS",     0);
   TARGETS               = XInternAtom(d, "TARGETS",             0);
   CLIPBOARD             = XInternAtom(d, "CLIPBOARD",           0);
+  TIMESTAMP             = XInternAtom(d, "TIMESTAMP",           0);
+  PRIMARY_TIMESTAMP     = XInternAtom(d, "PRIMARY_TIMESTAMP",   0);
+  CLIPBOARD_TIMESTAMP   = XInternAtom(d, "CLIPBOARD_TIMESTAMP", 0);
   fl_XdndAware          = XInternAtom(d, "XdndAware",           0);
   fl_XdndSelection      = XInternAtom(d, "XdndSelection",       0);
   fl_XdndEnter          = XInternAtom(d, "XdndEnter",           0);
@@ -625,6 +705,9 @@
   fl_XaTextUriList      = XInternAtom(d, "text/uri-list",       0);
   fl_NET_WM_NAME        = XInternAtom(d, "_NET_WM_NAME",        0);
   fl_NET_WM_ICON_NAME   = XInternAtom(d, "_NET_WM_ICON_NAME",   0);
+  fl_NET_SUPPORTING_WM_CHECK = XInternAtom(d, "_NET_SUPPORTING_WM_CHECK", 0);
+  fl_NET_WM_STATE       = XInternAtom(d, "_NET_WM_STATE",       0);
+  fl_NET_WM_STATE_FULLSCREEN = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 0);
 
   if (sizeof(Atom) < 4)
     atom_bits = sizeof(Atom) * 8;
@@ -646,6 +729,14 @@
 #if !USE_COLORMAP
   Fl::visual(FL_RGB);
 #endif
+
+#ifdef HAVE_XFIXES
+  int error_base;
+  if (XFixesQueryExtension(d, &xfixes_event_base, &error_base))
+    have_xfixes = true;
+  else
+    have_xfixes = false;
+#endif
 }
 
 void fl_close_display() {
@@ -768,6 +859,31 @@
   XSendEvent(fl_display, window, 0, 0, &e);
 }
 
+
+/* 
+   Get window property value (32 bit format) 
+   Returns zero on success, -1 on error
+*/
+static int get_xwinprop(Window wnd, Atom prop, long max_length,
+                        unsigned long *nitems, unsigned long **data) {
+  Atom actual;
+  int format;
+  unsigned long bytes_after;
+  
+  if (Success != XGetWindowProperty(fl_display, wnd, prop, 0, max_length, 
+                                    False, AnyPropertyType, &actual, &format, 
+                                    nitems, &bytes_after, (unsigned char**)data)) {
+    return -1;
+  }
+
+  if (actual == None || format != 32) {
+    return -1;
+  }
+
+  return 0;
+}
+
+
 ////////////////////////////////////////////////////////////////
 // Code for copying to clipboard and DnD out of the program:
 
@@ -787,6 +903,94 @@
 }
 
 ////////////////////////////////////////////////////////////////
+// Code for tracking clipboard changes:
+
+static Time primary_timestamp = -1;
+static Time clipboard_timestamp = -1;
+
+extern bool fl_clipboard_notify_empty(void);
+extern void fl_trigger_clipboard_notify(int source);
+
+static void poll_clipboard_owner(void) {
+  Window xid;
+
+  // No polling needed with Xfixes
+  if (have_xfixes)
+    return;
+
+  // No one is interested, so no point polling
+  if (fl_clipboard_notify_empty())
+    return;
+
+  // We need a window for this to work
+  if (!Fl::first_window())
+    return;
+  xid = fl_xid(Fl::first_window());
+  if (!xid)
+    return;
+
+  // Request an update of the selection time for both the primary and
+  // clipboard selections. Magic continues when we get a SelectionNotify.
+  if (!fl_i_own_selection[0])
+    XConvertSelection(fl_display, XA_PRIMARY, TIMESTAMP, PRIMARY_TIMESTAMP,
+                      xid, fl_event_time);
+  if (!fl_i_own_selection[1])
+    XConvertSelection(fl_display, CLIPBOARD, TIMESTAMP, CLIPBOARD_TIMESTAMP,
+                      xid, fl_event_time);
+}
+
+static void clipboard_timeout(void *data)
+{
+  // No one is interested, so stop polling
+  if (fl_clipboard_notify_empty())
+    return;
+
+  poll_clipboard_owner();
+
+  Fl::repeat_timeout(0.5, clipboard_timeout);
+}
+
+static void handle_clipboard_timestamp(int clipboard, Time time)
+{
+  Time *timestamp;
+
+  timestamp = clipboard ? &clipboard_timestamp : &primary_timestamp;
+
+  if (!have_xfixes) {
+    // Initial scan, just store the value
+    if (*timestamp == (Time)-1) {
+      *timestamp = time;
+      return;
+    }
+  }
+
+  // Same selection
+  if (time == *timestamp)
+    return;
+
+  *timestamp = time;
+
+  // Something happened! Let's tell someone!
+  fl_trigger_clipboard_notify(clipboard);
+}
+
+void fl_clipboard_notify_change() {
+  // Reset the timestamps if we've going idle so that you don't
+  // get a bogus immediate trigger next time they're activated.
+  if (fl_clipboard_notify_empty()) {
+    primary_timestamp = -1;
+    clipboard_timestamp = -1;
+  } else {
+    if (!have_xfixes) {
+      poll_clipboard_owner();
+
+      if (!Fl::has_timeout(clipboard_timeout))
+        Fl::add_timeout(0.5, clipboard_timeout);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////
 
 const XEvent* fl_xevent; // the current x event
 ulong fl_event_time; // the last timestamp from an x event
@@ -864,10 +1068,9 @@
   XEvent xevent = thisevent;
   fl_xevent = &thisevent;
   Window xid = xevent.xany.window;
-  static Window xim_win = 0;
 
   if (fl_xim_ic && xevent.type == DestroyNotify &&
-        xid != xim_win && !fl_find(xid))
+        xid != fl_xim_win && !fl_find(xid))
   {
     XIM xim_im;
     xim_im = XOpenIM(fl_display, NULL, NULL, NULL);
@@ -882,49 +1085,11 @@
     return 0;
   }
 
-  if (fl_xim_ic && (xevent.type == FocusIn))
-  {
-#define POOR_XIM
-#ifdef POOR_XIM
-        if (xim_win != xid)
-        {
-                xim_win  = xid;
-                XDestroyIC(fl_xim_ic);
-                fl_xim_ic = NULL;
-                fl_new_ic();
-                XSetICValues(fl_xim_ic,
-                                XNFocusWindow, xevent.xclient.window,
-                                XNClientWindow, xid,
-                                NULL);
-        }
-        fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
-#else
-    if (Fl::first_window() && Fl::first_window()->modal()) {
-      Window x  = fl_xid(Fl::first_window());
-      if (x != xim_win) {
-        xim_win  = x;
-        XSetICValues(fl_xim_ic,
-                        XNFocusWindow, xim_win,
-                        XNClientWindow, xim_win,
-                        NULL);
-        fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
-      }
-    } else if (xim_win != xid && xid) {
-      xim_win = xid;
-      XSetICValues(fl_xim_ic,
-                        XNFocusWindow, xevent.xclient.window,
-                        XNClientWindow, xid,
-                        //XNFocusWindow, xim_win,
-                        //XNClientWindow, xim_win,
-                        NULL);
-      fl_set_spot(spotf, spots, spot.x, spot.y, spot.width, spot.height);
-    }
-#endif
+  if (fl_xim_ic) {
+    if (XFilterEvent((XEvent *)&xevent, 0))
+      return 1;
   }
 
-  if ( XFilterEvent((XEvent *)&xevent, 0) )
-      return(1);
-
   switch (xevent.type) {
 
   case KeymapNotify:
@@ -936,7 +1101,6 @@
     return 0;
 
   case SelectionNotify: {
-    if (!fl_selection_requestor) return 0;
     static unsigned char* buffer = 0;
     if (buffer) {XFree(buffer); buffer = 0;}
     long bytesread = 0;
@@ -952,6 +1116,19 @@
                              bytesread/4, 65536, 1, 0,
                              &actual, &format, &count, &remaining,
                              &portion)) break; // quit on error
+
+      if ((fl_xevent->xselection.property == PRIMARY_TIMESTAMP) ||
+          (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP)) {
+        if (portion && format == 32 && count == 1) {
+          Time t = *(unsigned int*)portion;
+          if (fl_xevent->xselection.property == CLIPBOARD_TIMESTAMP)
+            handle_clipboard_timestamp(1, t);
+          else
+            handle_clipboard_timestamp(0, t);
+        }
+        return true;
+      }
+
       if (actual == TARGETS || actual == XA_ATOM) {
 	Atom type = XA_STRING;
 	for (unsigned i = 0; i<count; i++) {
@@ -988,6 +1165,9 @@
       buffer[bytesread] = 0;
       convert_crlf(buffer, bytesread);
     }
+
+    if (!fl_selection_requestor) return 0;
+
     Fl::e_text = buffer ? (char*)buffer : (char *)"";
     Fl::e_length = bytesread;
     int old_event = Fl::e_number;
@@ -1008,6 +1188,7 @@
   case SelectionClear: {
     int clipboard = fl_xevent->xselectionclear.selection == CLIPBOARD;
     fl_i_own_selection[clipboard] = 0;
+    poll_clipboard_owner();
     return 1;}
 
   case SelectionRequest: {
@@ -1220,6 +1401,9 @@
   case FocusIn:
     if (fl_xim_ic) XSetICFocus(fl_xim_ic);
     event = FL_FOCUS;
+    // If the user has toggled from another application to this one,
+    // then it's a good time to check for clipboard changes.
+    poll_clipboard_owner();
     break;
 
   case FocusOut:
@@ -1260,15 +1444,15 @@
         //static XComposeStatus compose;
         len = XLookupString((XKeyEvent*)&(xevent.xkey),
                              buffer, buffer_len, &keysym, 0/*&compose*/);
-        if (keysym && keysym < 0x400) { // a character in latin-1,2,3,4 sets
-          // force it to type a character (not sure if this ever is needed):
-          // if (!len) {buffer[0] = char(keysym); len = 1;}
-          len = fl_utf8encode(XKeysymToUcs(keysym), buffer);
-          if (len < 1) len = 1;
-          // ignore all effects of shift on the keysyms, which makes it a lot
-          // easier to program shortcuts and is Windoze-compatible:
-          keysym = XKeycodeToKeysym(fl_display, keycode, 0);
-        }
+        // XLookupString() is only defined to return Latin-1 (although it
+        // often gives you more). To be safe, use our own lookups based on
+        // keysym.
+        len = fl_utf8encode(XKeysymToUcs(keysym), buffer);
+        if (len < 1)
+          len = 1;
+        // ignore all effects of shift on the keysyms, which makes it a lot
+        // easier to program shortcuts and is Windoze-compatable:
+        keysym = XKeycodeToKeysym(fl_display, keycode, 0);
       }
       // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not
       //      set until set_event_xy() is called later...
@@ -1440,12 +1624,19 @@
   case ButtonPress:
     Fl::e_keysym = FL_Button + xevent.xbutton.button;
     set_event_xy();
+    Fl::e_dx = Fl::e_dy = 0;
     if (xevent.xbutton.button == Button4) {
       Fl::e_dy = -1; // Up
       event = FL_MOUSEWHEEL;
     } else if (xevent.xbutton.button == Button5) {
       Fl::e_dy = +1; // Down
       event = FL_MOUSEWHEEL;
+    } else if (xevent.xbutton.button == 6) {
+      Fl::e_dx = -1; // Left
+      event = FL_MOUSEWHEEL;
+    } else if (xevent.xbutton.button == 7) {
+      Fl::e_dx = +1; // Right
+      event = FL_MOUSEWHEEL;
     } else {
       Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1));
       event = FL_PUSH;
@@ -1456,6 +1647,31 @@
     in_a_window = true;
     break;
 
+  case PropertyNotify:
+    if (xevent.xproperty.atom == fl_NET_WM_STATE) {
+      int fullscreen_state = 0;
+      if (xevent.xproperty.state != PropertyDelete) {
+        unsigned long nitems;
+        unsigned long *words = 0;
+        if (0 == get_xwinprop(xid, fl_NET_WM_STATE, 64, &nitems, &words) ) { 
+          for (unsigned long item = 0; item < nitems; item++) {
+            if (words[item] == fl_NET_WM_STATE_FULLSCREEN) {
+              fullscreen_state = 1;
+            }
+          }
+        }
+      }
+      if (window->fullscreen_active() && !fullscreen_state) {
+        window->_clear_fullscreen();
+        event = FL_FULLSCREEN;
+      }
+      if (!window->fullscreen_active() && fullscreen_state) {
+        window->_set_fullscreen();
+        event = FL_FULLSCREEN;
+      }
+    }
+    break;
+
   case MotionNotify:
     set_event_xy();
 #  if CONSOLIDATE_MOTION
@@ -1556,6 +1772,25 @@
     }
   }
 
+#ifdef HAVE_XFIXES
+  switch (xevent.type - xfixes_event_base) {
+  case XFixesSelectionNotify: {
+    // Someone feeding us bogus events?
+    if (!have_xfixes)
+      return true;
+
+    XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)&xevent;
+
+    if ((selection_notify->selection == XA_PRIMARY) && !fl_i_own_selection[0])
+      handle_clipboard_timestamp(0, selection_notify->selection_timestamp);
+    else if ((selection_notify->selection == CLIPBOARD) && !fl_i_own_selection[1])
+      handle_clipboard_timestamp(1, selection_notify->selection_timestamp);
+
+    return true;
+    }
+  }
+#endif
+
   return Fl::handle(event, window);
 }
 
@@ -1595,6 +1830,75 @@
 
 ////////////////////////////////////////////////////////////////
 
+#define _NET_WM_STATE_REMOVE        0  /* remove/unset property */
+#define _NET_WM_STATE_ADD           1  /* add/set property */
+#define _NET_WM_STATE_TOGGLE        2  /* toggle property  */
+
+static void send_wm_state_event(Window wnd, int add, Atom prop) {
+  XEvent e;
+  e.xany.type = ClientMessage;
+  e.xany.window = wnd;
+  e.xclient.message_type = fl_NET_WM_STATE;
+  e.xclient.format = 32;
+  e.xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+  e.xclient.data.l[1] = prop;
+  e.xclient.data.l[2] = 0;
+  e.xclient.data.l[3] = 0;
+  e.xclient.data.l[4] = 0;
+  XSendEvent(fl_display, RootWindow(fl_display, fl_screen),
+             0, SubstructureNotifyMask | SubstructureRedirectMask,
+             &e);
+}
+
+int ewmh_supported() {
+  static int result = -1;
+
+  if (result == -1) {
+    result = 0;
+    unsigned long nitems;
+    unsigned long *words = 0;
+    if (0 == get_xwinprop(XRootWindow(fl_display, fl_screen), fl_NET_SUPPORTING_WM_CHECK, 64,
+                          &nitems, &words) && nitems == 1) {
+      Window child = words[0];
+      if (0 == get_xwinprop(child, fl_NET_SUPPORTING_WM_CHECK, 64,
+                           &nitems, &words) && nitems == 1) {
+        result = (child == words[0]);
+      }
+    }
+  }
+
+  return result;
+}
+
+/* Change an existing window to fullscreen */
+void fullscreen_x(Fl_Window *w) {
+  if (ewmh_supported()) {
+    send_wm_state_event(fl_xid(w), 1, fl_NET_WM_STATE_FULLSCREEN);
+  } else {
+    w->_set_fullscreen();
+    w->hide();
+    w->show();
+    /* We want to grab the window, not a widget, so we cannot use Fl::grab */
+    XGrabKeyboard(fl_display, fl_xid(w), 1, GrabModeAsync, GrabModeAsync, fl_event_time);
+    Fl::handle(FL_FULLSCREEN, w);
+  }
+}
+
+void fullscreen_off_x(Fl_Window *w, int X, int Y, int W, int H) {
+  if (ewmh_supported()) {
+    send_wm_state_event(fl_xid(w), 0, fl_NET_WM_STATE_FULLSCREEN);
+  } else {
+    w->_clear_fullscreen();
+    /* The grab will be lost when the window is destroyed */
+    w->hide();
+    w->resize(X,Y,W,H);
+    w->show();
+    Fl::handle(FL_FULLSCREEN, w);
+  }
+}
+
+////////////////////////////////////////////////////////////////
+
 // A subclass of Fl_Window may call this to associate an X window it
 // creates with the Fl_Window:
 
@@ -1630,6 +1934,7 @@
 |KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask
 |ButtonPressMask|ButtonReleaseMask
 |EnterWindowMask|LeaveWindowMask
+|PropertyChangeMask
 |PointerMotionMask;
 
 void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
@@ -1701,6 +2006,16 @@
     attr.save_under = 1; mask |= CWSaveUnder;
     if (!win->border()) {attr.override_redirect = 1; mask |= CWOverrideRedirect;}
   }
+  // For the non-EWMH fullscreen case, we cannot use the code above,
+  // since we do not want save_under, do not want to turn off the
+  // border, and cannot grab without an existing window. Besides, 
+  // there is no clear_override(). 
+  if (win->flags() & Fl_Widget::FULLSCREEN && !ewmh_supported()) {
+    attr.override_redirect = 1;
+    mask |= CWOverrideRedirect;
+    Fl::screen_xywh(X, Y, W, H, X, Y, W, H);
+  }
+
   if (fl_background_pixel >= 0) {
     attr.background_pixel = fl_background_pixel;
     fl_background_pixel = -1;
@@ -1760,6 +2075,12 @@
           PropModeAppend, (unsigned char*) &net_wm_state_skip_taskbar, 1);
     }
 
+    // If asked for, create fullscreen
+    if (win->flags() & Fl_Widget::FULLSCREEN && ewmh_supported()) {
+      XChangeProperty (fl_display, xp->xid, fl_NET_WM_STATE, XA_ATOM, 32,
+                       PropModeAppend, (unsigned char*) &fl_NET_WM_STATE_FULLSCREEN, 1);
+    }
+
     // Make it receptive to DnD:
     long version = 4;
     XChangeProperty(fl_display, xp->xid, fl_XdndAware,
@@ -1789,6 +2110,16 @@
     XChangeProperty(fl_display, xp->xid, net_wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&net_wm_type_kind, 1);
   }
 
+#ifdef HAVE_XFIXES
+  // register for clipboard change notifications
+  if (have_xfixes && !win->parent()) {
+    XFixesSelectSelectionInput(fl_display, xp->xid, XA_PRIMARY,
+                               XFixesSetSelectionOwnerNotifyMask);
+    XFixesSelectSelectionInput(fl_display, xp->xid, CLIPBOARD,
+                               XFixesSetSelectionOwnerNotifyMask);
+  }
+#endif
+
   XMapWindow(fl_display, xp->xid);
   if (showit) {
     win->set_visible();
@@ -1797,6 +2128,12 @@
     Fl::e_number = old_event;
     win->redraw();
   }
+
+  // non-EWMH fullscreen case, need grab
+  if (win->flags() & Fl_Widget::FULLSCREEN && !ewmh_supported()) {
+    XGrabKeyboard(fl_display, xp->xid, 1, GrabModeAsync, GrabModeAsync, fl_event_time);
+  }
+
 }
 
 ////////////////////////////////////////////////////////////////
@@ -1883,6 +2220,94 @@
 
 ////////////////////////////////////////////////////////////////
 
+int Fl_X::set_cursor(Fl_Cursor c) {
+  unsigned int shape;
+  Cursor xc;
+
+  switch (c) {
+  case FL_CURSOR_ARROW:   shape = XC_left_ptr; break;
+  case FL_CURSOR_CROSS:   shape = XC_tcross; break;
+  case FL_CURSOR_WAIT:    shape = XC_watch; break;
+  case FL_CURSOR_INSERT:  shape = XC_xterm; break;
+  case FL_CURSOR_HAND:    shape = XC_hand2; break;
+  case FL_CURSOR_HELP:    shape = XC_question_arrow; break;
+  case FL_CURSOR_MOVE:    shape = XC_fleur; break;
+  case FL_CURSOR_NS:      shape = XC_sb_v_double_arrow; break;
+  case FL_CURSOR_WE:      shape = XC_sb_h_double_arrow; break;
+  case FL_CURSOR_NE:      shape = XC_top_right_corner; break;
+  case FL_CURSOR_N:       shape = XC_top_side; break;
+  case FL_CURSOR_NW:      shape = XC_top_left_corner; break;
+  case FL_CURSOR_E:       shape = XC_right_side; break;
+  case FL_CURSOR_W:       shape = XC_left_side; break;
+  case FL_CURSOR_SE:      shape = XC_bottom_right_corner; break;
+  case FL_CURSOR_S:       shape = XC_bottom_side; break;
+  case FL_CURSOR_SW:      shape = XC_bottom_left_corner; break;
+  default:
+    return 0;
+  }
+
+  xc = XCreateFontCursor(fl_display, shape);
+  XDefineCursor(fl_display, xid, xc);
+  XFreeCursor(fl_display, xc);
+
+  return 1;
+}
+
+int Fl_X::set_cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
+#if ! HAVE_XCURSOR
+  return 0;
+#else
+  XcursorImage *cursor;
+  Cursor xc;
+
+  if ((hotx < 0) || (hotx >= image->w()))
+    return 0;
+  if ((hoty < 0) || (hoty >= image->h()))
+    return 0;
+
+  cursor = XcursorImageCreate(image->w(), image->h());
+  if (!cursor)
+    return 0;
+
+  const uchar *i = (const uchar*)*image->data();
+  XcursorPixel *o = cursor->pixels;
+  for (int y = 0;y < image->h();y++) {
+    for (int x = 0;x < image->w();x++) {
+      switch (image->d()) {
+      case 1:
+        *o = (0xff<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
+        break;
+      case 2:
+        *o = (i[1]<<24) | (i[0]<<16) | (i[0]<<8) | i[0];
+        break;
+      case 3:
+        *o = (0xff<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
+        break;
+      case 4:
+        *o = (i[3]<<24) | (i[0]<<16) | (i[1]<<8) | i[2];
+        break;
+      }
+      i += image->d();
+      o++;
+    }
+    i += image->ld();
+  }
+
+  cursor->xhot = hotx;
+  cursor->yhot = hoty;
+
+  xc = XcursorImageLoadCursor(fl_display, cursor);
+  XDefineCursor(fl_display, xid, xc);
+  XFreeCursor(fl_display, xc);
+
+  XcursorImageDestroy(cursor);
+
+  return 1;
+#endif
+}
+
+////////////////////////////////////////////////////////////////
+
 // returns pointer to the filename, or null if name ends with '/'
 const char *fl_filename_name(const char *name) {
   const char *p,*q;
diff --git a/common/fltk/src/fl_cursor.cxx b/common/fltk/src/fl_cursor.cxx
index 6649255..bad3936 100644
--- a/common/fltk/src/fl_cursor.cxx
+++ b/common/fltk/src/fl_cursor.cxx
@@ -33,300 +33,155 @@
 
 #include <FL/Fl.H>
 #include <FL/Fl_Window.H>
+#include <FL/Fl_Pixmap.H>
+#include <FL/Fl_RGB_Image.H>
 #include <FL/x.H>
-#if !defined(WIN32) && !defined(__APPLE__)
-#  include <X11/cursorfont.h>
-#endif
 #include <FL/fl_draw.H>
 
+#include "fl_cursor_wait.xpm"
+#include "fl_cursor_help.xpm"
+#include "fl_cursor_nwse.xpm"
+#include "fl_cursor_nesw.xpm"
+#include "fl_cursor_none.xpm"
+
 /**
   Sets the cursor for the current window to the specified shape and colors.
   The cursors are defined in the <FL/Enumerations.H> header file. 
   */
+void fl_cursor(Fl_Cursor c) {
+  if (Fl::first_window()) Fl::first_window()->cursor(c);
+}
+
+/* For back compatibility only. */
 void fl_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) {
-  if (Fl::first_window()) Fl::first_window()->cursor(c,fg,bg);
+  fl_cursor(c);
 }
+
+
 /** 
-    Sets the default window cursor as well as its color.
+    Sets the default window cursor. This is the cursor that will be used
+    after the mouse pointer leaves a widget with a custom cursor set.
 
-    For back compatibility only.
+    \see cursor(const Fl_RGB_Image*, int, int), default_cursor()
 */
-void Fl_Window::default_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) {
-//  if (c == FL_CURSOR_DEFAULT) c = FL_CURSOR_ARROW;
-
+void Fl_Window::default_cursor(Fl_Cursor c) {
   cursor_default = c;
-  cursor_fg      = fg;
-  cursor_bg      = bg;
-
-  cursor(c, fg, bg);
+  cursor(c);
 }
 
-#ifdef WIN32
 
-#  ifndef IDC_HAND
-#    define IDC_HAND	MAKEINTRESOURCE(32649)
-#  endif // !IDC_HAND
+void fallback_cursor(Fl_Window *w, Fl_Cursor c) {
+  const char **xpm;
+  int hotx, hoty;
 
-void Fl_Window::cursor(Fl_Cursor c, Fl_Color c1, Fl_Color c2) {
-  if (!shown()) return;
+  // The standard arrow is our final fallback, so something is broken
+  // if we get called back here with that as an argument.
+  if (c == FL_CURSOR_ARROW)
+    return;
+
+  switch (c) {
+  case FL_CURSOR_WAIT:
+    xpm = (const char**)fl_cursor_wait_xpm;
+    hotx = 8;
+    hoty = 15;
+    break;
+  case FL_CURSOR_HELP:
+    xpm = (const char**)fl_cursor_help_xpm;
+    hotx = 1;
+    hoty = 3;
+    break;
+  case FL_CURSOR_NWSE:
+    xpm = (const char**)fl_cursor_nwse_xpm;
+    hotx = 7;
+    hoty = 7;
+    break;
+  case FL_CURSOR_NESW:
+    xpm = (const char**)fl_cursor_nesw_xpm;
+    hotx = 7;
+    hoty = 7;
+    break;
+  case FL_CURSOR_NONE:
+    xpm = (const char**)fl_cursor_none_xpm;
+    hotx = 0;
+    hoty = 0;
+    break;
+  default:
+    w->cursor(FL_CURSOR_ARROW);
+    return;
+  }
+
+  Fl_Pixmap pxm(xpm);
+  Fl_RGB_Image image(&pxm);
+
+  w->cursor(&image, hotx, hoty);
+}
+
+
+void Fl_Window::cursor(Fl_Cursor c) {
+  int ret;
+
   // the cursor must be set for the top level window, not for subwindows
   Fl_Window *w = window(), *toplevel = this;
-  while (w) { toplevel = w; w = w->window(); }
-  if (toplevel != this) { toplevel->cursor(c, c1, c2); return; }
-  // now set the actual cursor
-  if (c == FL_CURSOR_DEFAULT) {
+
+  while (w) {
+    toplevel = w;
+    w = w->window();
+  }
+
+  if (toplevel != this) {
+    toplevel->cursor(c);
+    return;
+  }
+
+  if (c == FL_CURSOR_DEFAULT)
     c = cursor_default;
-  }
-  if (c > FL_CURSOR_NESW) {
-    i->cursor = 0;
-  } else if (c == FL_CURSOR_DEFAULT) {
-    i->cursor = fl_default_cursor;
-  } else {
-    LPSTR n;
-    switch (c) {
-    case FL_CURSOR_ARROW:	n = IDC_ARROW; break;
-    case FL_CURSOR_CROSS:	n = IDC_CROSS; break;
-    case FL_CURSOR_WAIT:	n = IDC_WAIT; break;
-    case FL_CURSOR_INSERT:	n = IDC_IBEAM; break;
-    case FL_CURSOR_HELP:	n = IDC_HELP; break;
-    case FL_CURSOR_HAND: {
-          OSVERSIONINFO osvi;
 
-          // Get the OS version: Windows 98 and 2000 have a standard
-	  // hand cursor.
-          memset(&osvi, 0, sizeof(OSVERSIONINFO));
-          osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-          GetVersionEx(&osvi);
+  if (!i)
+    return;
 
-          if (osvi.dwMajorVersion > 4 ||
-  	      (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion > 0 &&
-  	       osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) n = IDC_HAND;
-          else n = IDC_UPARROW;
-	} break;
-    case FL_CURSOR_MOVE:	n = IDC_SIZEALL; break;
-    case FL_CURSOR_N:
-    case FL_CURSOR_S:
-    case FL_CURSOR_NS:		n = IDC_SIZENS; break;
-    case FL_CURSOR_NE:
-    case FL_CURSOR_SW:
-    case FL_CURSOR_NESW:	n = IDC_SIZENESW; break;
-    case FL_CURSOR_E:
-    case FL_CURSOR_W:
-    case FL_CURSOR_WE:		n = IDC_SIZEWE; break;
-    case FL_CURSOR_SE:
-    case FL_CURSOR_NW:
-    case FL_CURSOR_NWSE:	n = IDC_SIZENWSE; break;
-    default:			n = IDC_NO; break;
-    }
-    i->cursor = LoadCursor(NULL, n);
-  }
-  SetCursor(i->cursor);
+  ret = i->set_cursor(c);
+  if (ret)
+    return;
+
+  fallback_cursor(this, c);
 }
 
-#elif defined(__APPLE__)
+/**
+  Changes the cursor for this window.  This always calls the system, if
+  you are changing the cursor a lot you may want to keep track of how
+  you set it in a static variable and call this only if the new cursor
+  is different.
 
-#ifdef __BIG_ENDIAN__
-# define E(x) x
-#elif defined __LITTLE_ENDIAN__
-// Don't worry. This will be resolved at compile time
-# define E(x) (x>>8)|((x<<8)&0xff00)
-#else
-# error "Either __LITTLE_ENDIAN__ or __BIG_ENDIAN__ must be defined"
-#endif
+  The default cursor will be used if the provided image cannot be used
+  as a cursor.
 
-extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
+  \see cursor(Fl_Cursor), default_cursor()
+*/
+void Fl_Window::cursor(const Fl_RGB_Image *image, int hotx, int hoty) {
+  int ret;
 
+  // the cursor must be set for the top level window, not for subwindows
+  Fl_Window *w = window(), *toplevel = this;
 
-CGContextRef Fl_X::help_cursor_image(void)
-{
-  int w = 20, h = 20;
-  Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
-  fl_begin_offscreen(off);
-  CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
-  fl_rectf(0,0,w,h);
-  fl_color(FL_BLACK);
-  fl_font(FL_COURIER_BOLD, 20);
-  fl_draw("?", 1, h-1);
-  fl_end_offscreen();
-  return (CGContextRef)off;
-}
-
-CGContextRef Fl_X::none_cursor_image(void)
-{
-  int w = 20, h = 20;
-  Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
-  fl_begin_offscreen(off);
-  CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
-  fl_rectf(0,0,w,h);
-  fl_end_offscreen();
-  return (CGContextRef)off;
-}
-
-CGContextRef Fl_X::watch_cursor_image(void)
-{
-  int w, h, r = 5;
-  w = 2*r+6;
-  h = 4*r;
-  Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
-  fl_begin_offscreen(off);
-  CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
-  fl_rectf(0,0,w,h);
-  CGContextTranslateCTM( (CGContextRef)off, w/2, h/2);
-  fl_color(FL_WHITE);
-  fl_circle(0, 0, r+1);
-  fl_color(FL_BLACK);
-  fl_rectf(int(-r*0.7), int(-r*1.7), int(1.4*r), int(3.4*r));
-  fl_rectf(r-1, -1, 3, 3);
-  fl_color(FL_WHITE);
-  fl_pie(-r, -r, 2*r, 2*r, 0, 360);
-  fl_color(FL_BLACK);
-  fl_circle(0,0,r);
-  fl_xyline(0, 0, int(-r*.7));
-  fl_xyline(0, 0, 0, int(-r*.7));
-  fl_end_offscreen();
-  return (CGContextRef)off;
-}
-
-CGContextRef Fl_X::nesw_cursor_image(void)
-{
-  int c = 7, r = 2*c;
-  int w = r, h = r;
-  Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
-  fl_begin_offscreen(off);
-  CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
-  fl_rectf(0,0,w,h);
-  CGContextTranslateCTM( (CGContextRef)off, 0, h);
-  CGContextScaleCTM( (CGContextRef)off, 1, -1);
-  fl_color(FL_BLACK);
-  fl_polygon(0, 0, c, 0, 0, c);
-  fl_polygon(r, r, r, r-c, r-c, r);
-  fl_line_style(FL_SOLID, 2, 0);
-  fl_line(0,1, r,r+1);
-  fl_line_style(FL_SOLID, 0, 0);
-  fl_end_offscreen();
-  return (CGContextRef)off;
-}
-
-CGContextRef Fl_X::nwse_cursor_image(void)
-{
-  int c = 7, r = 2*c;
-  int w = r, h = r;
-  Fl_Offscreen off = fl_create_offscreen_with_alpha(w, h);
-  fl_begin_offscreen(off);
-  CGContextSetRGBFillColor( (CGContextRef)off, 0,0,0,0);
-  fl_rectf(0,0,w,h);
-  CGContextTranslateCTM( (CGContextRef)off, 0, h);
-  CGContextScaleCTM( (CGContextRef)off, 1, -1);
-  fl_color(FL_BLACK);
-  fl_polygon(r-1, 0, r-1, c, r-1-c, 0);
-  fl_polygon(-1, r, c-1, r, -1, r-c);
-  fl_line_style(FL_SOLID, 2, 0);
-  fl_line(r-1,1, -1,r+1);
-  fl_line_style(FL_SOLID, 0, 0);
-  fl_end_offscreen();
-  return (CGContextRef)off;
-}
-
-void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) {
-  if (c == FL_CURSOR_DEFAULT) {
-    c = cursor_default;
-  }
-  if (i) i->set_cursor(c);
-}
-
-#else
-
-// I like the MSWindows resize cursors, so I duplicate them here:
-
-#define CURSORSIZE 16
-#define HOTXY 7
-static struct TableEntry {
-  uchar bits[CURSORSIZE*CURSORSIZE/8];
-  uchar mask[CURSORSIZE*CURSORSIZE/8];
-  Cursor cursor;
-} table[] = {
-  {{	// FL_CURSOR_NS
-   0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0x80, 0x01, 0x80, 0x01,
-   0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
-   0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00},
-   {
-   0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xc0, 0x03,
-   0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xf0, 0x0f,
-   0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01}},
-  {{	// FL_CURSOR_EW
-   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10,
-   0x0c, 0x30, 0xfe, 0x7f, 0xfe, 0x7f, 0x0c, 0x30, 0x08, 0x10, 0x00, 0x00,
-   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
-   {
-   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x1c, 0x38,
-   0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18,
-   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
-  {{	// FL_CURSOR_NWSE
-   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x38, 0x00, 0x78, 0x00,
-   0xe8, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x1c,
-   0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
-   {
-   0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x7c, 0x00, 0xfc, 0x00,
-   0xfc, 0x01, 0xec, 0x03, 0xc0, 0x37, 0x80, 0x3f, 0x00, 0x3f, 0x00, 0x3e,
-   0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00}},
-  {{	// FL_CURSOR_NESW
-   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1e,
-   0x00, 0x17, 0x80, 0x03, 0xc0, 0x01, 0xe8, 0x00, 0x78, 0x00, 0x38, 0x00,
-   0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
-   {
-   0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3f,
-   0x80, 0x3f, 0xc0, 0x37, 0xec, 0x03, 0xfc, 0x01, 0xfc, 0x00, 0x7c, 0x00,
-   0xfc, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00}},
-  {{0}, {0}} // FL_CURSOR_NONE & unknown
-};
-
-void Fl_Window::cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) {
-  if (!shown()) return;
-  Cursor xc;
-  int deleteit = 0;
-  if (c == FL_CURSOR_DEFAULT) {
-    c  = cursor_default;
-    fg = cursor_fg;
-    bg = cursor_bg;
+  while (w) {
+    toplevel = w;
+    w = w->window();
   }
 
-  if (!c) {
-    xc = None;
-  } else {
-    if (c >= FL_CURSOR_NS) {
-      TableEntry *q = (c > FL_CURSOR_NESW) ? table+4 : table+(c-FL_CURSOR_NS);
-      if (!(q->cursor)) {
-	XColor dummy = { 0 };
-	Pixmap p = XCreateBitmapFromData(fl_display,
-	  RootWindow(fl_display, fl_screen), (const char*)(q->bits),
-	  CURSORSIZE, CURSORSIZE);
-	Pixmap m = XCreateBitmapFromData(fl_display,
-	  RootWindow(fl_display, fl_screen), (const char*)(q->mask),
-	  CURSORSIZE, CURSORSIZE);
-	q->cursor = XCreatePixmapCursor(fl_display, p,m,&dummy, &dummy,
-					HOTXY, HOTXY);
-	XFreePixmap(fl_display, m);
-	XFreePixmap(fl_display, p);
-      }
-      xc = q->cursor;
-    } else {
-      xc = XCreateFontCursor(fl_display, (c-1)*2);
-      deleteit = 1;
-    }
-    XColor fgc;
-    uchar r,g,b;
-    Fl::get_color(fg,r,g,b);
-    fgc.red = r<<8; fgc.green = g<<8; fgc.blue = b<<8;
-    XColor bgc;
-    Fl::get_color(bg,r,g,b);
-    bgc.red = r<<8; bgc.green = g<<8; bgc.blue = b<<8;
-    XRecolorCursor(fl_display, xc, &fgc, &bgc);
+  if (toplevel != this) {
+    toplevel->cursor(image, hotx, hoty);
+    return;
   }
-  XDefineCursor(fl_display, fl_xid(this), xc);
-  if (deleteit) XFreeCursor(fl_display, xc);
-}
 
-#endif
+  if (!i)
+    return;
+
+  ret = i->set_cursor(image, hotx, hoty);
+  if (ret)
+    return;
+
+  cursor(FL_CURSOR_DEFAULT);
+}
 
 //
 // End of "$Id: fl_cursor.cxx 8055 2010-12-18 22:31:01Z manolo $".
diff --git a/common/fltk/src/fl_cursor_help.xpm b/common/fltk/src/fl_cursor_help.xpm
new file mode 100644
index 0000000..2d5b257
--- /dev/null
+++ b/common/fltk/src/fl_cursor_help.xpm
@@ -0,0 +1,95 @@
+/* XPM */
+static const char * fl_cursor_help_xpm[] = {
+"16 27 65 1",
+" 	c None",
+".	c #FFFFFF",
+"+	c #E2E2E2",
+"@	c #1C1C1C",
+"#	c #E7E7E7",
+"$	c #000000",
+"%	c #212121",
+"&	c #EAEAEA",
+"*	c #262626",
+"=	c #EDEDED",
+"-	c #2C2C2C",
+";	c #F0F0F0",
+">	c #333333",
+",	c #F1F1F1",
+"'	c #393939",
+")	c #F3F3F3",
+"!	c #404040",
+"~	c #484848",
+"{	c #F4F4F4",
+"]	c #050505",
+"^	c #202020",
+"/	c #707070",
+"(	c #F5F5F5",
+"_	c #040404",
+":	c #E1E1E1",
+"<	c #EEEEEE",
+"[	c #EFEFEF",
+"}	c #FEFEFE",
+"|	c #3D3D3D",
+"1	c #7E7E7E",
+"2	c #696969",
+"3	c #414141",
+"4	c #131313",
+"5	c #080808",
+"6	c #454545",
+"7	c #F2F2F2",
+"8	c #878787",
+"9	c #7D7D7D",
+"0	c #101010",
+"a	c #111111",
+"b	c #FDFDFD",
+"c	c #8A8A8A",
+"d	c #E6E6E6",
+"e	c #7B7B7B",
+"f	c #4C4C4C",
+"g	c #5C5C5C",
+"h	c #9F9F9F",
+"i	c #F9F9F9",
+"j	c #F7F7F7",
+"k	c #B1B1B1",
+"l	c #2E2E2E",
+"m	c #767676",
+"n	c #DCDCDC",
+"o	c #DEDEDE",
+"p	c #C7C7C7",
+"q	c #1B1B1B",
+"r	c #6B6B6B",
+"s	c #575757",
+"t	c #797979",
+"u	c #020202",
+"v	c #010101",
+"w	c #FBFBFB",
+"x	c #D7D7D7",
+"y	c #D8D8D8",
+"z	c #060606",
+"                ",
+".               ",
+".+              ",
+".@#             ",
+".$%&            ",
+".$$*=           ",
+".$$$-;          ",
+".$$$$>,         ",
+".$$$$$')        ",
+".$$$$$$!)       ",
+".$$$$$$$~{      ",
+".$$$$]^^^/(     ",
+".$$$$_:(<<[}    ",
+".$$|1$2<        ",
+".$3,(45[        ",
+".67 78$9,       ",
+".7   {0a( ....  ",
+"b    ,c5[defgh, ",
+"      )ijk_la$m.",
+"         no.p$q.",
+"           .r$s.",
+"          .t$-= ",
+"          7uv+  ",
+"          wxy.  ",
+"          :$z.  ",
+"          :$z.  ",
+"          ....  "};
diff --git a/common/fltk/src/fl_cursor_nesw.xpm b/common/fltk/src/fl_cursor_nesw.xpm
new file mode 100644
index 0000000..5a7113a
--- /dev/null
+++ b/common/fltk/src/fl_cursor_nesw.xpm
@@ -0,0 +1,46 @@
+/* XPM */
+static const char * fl_cursor_nesw_xpm[] = {
+"15 15 28 1",
+" 	c None",
+".	c #FFFFFF",
+"+	c #767676",
+"@	c #000000",
+"#	c #4E4E4E",
+"$	c #0C0C0C",
+"%	c #494949",
+"&	c #4D4D4D",
+"*	c #1B1B1B",
+"=	c #515151",
+"-	c #646464",
+";	c #363636",
+">	c #6A6A6A",
+",	c #545454",
+"'	c #585858",
+")	c #242424",
+"!	c #797979",
+"~	c #2E2E2E",
+"{	c #444444",
+"]	c #3B3B3B",
+"^	c #0A0A0A",
+"/	c #595959",
+"(	c #F7F7F7",
+"_	c #080808",
+":	c #6B6B6B",
+"<	c #FDFDFD",
+"[	c #FCFCFC",
+"}	c #FEFEFE",
+"     ..........",
+"      .+@@@@@@.",
+"       .#@@@@@.",
+"        .$@@@@.",
+"       .%@@@@@.",
+".     .&@@@*@@.",
+"..   .=@@@-.;@.",
+".>. .,@@@'. .).",
+".@!.'@@@#.   ..",
+".@@~@@@{.     .",
+".@@@@@].       ",
+".@@@@^.        ",
+".@@@@@/(       ",
+".______:(      ",
+"<[[[[[[[[}     "};
diff --git a/common/fltk/src/fl_cursor_none.xpm b/common/fltk/src/fl_cursor_none.xpm
new file mode 100644
index 0000000..054e461
--- /dev/null
+++ b/common/fltk/src/fl_cursor_none.xpm
@@ -0,0 +1,19 @@
+/* XPM */
+static const char * fl_cursor_none_xpm[] = {
+"15 15 1 1",
+" 	c None",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               ",
+"               "};
diff --git a/common/fltk/src/fl_cursor_nwse.xpm b/common/fltk/src/fl_cursor_nwse.xpm
new file mode 100644
index 0000000..d495eb4
--- /dev/null
+++ b/common/fltk/src/fl_cursor_nwse.xpm
@@ -0,0 +1,46 @@
+/* XPM */
+static const char * fl_cursor_nwse_xpm[] = {
+"15 15 28 1",
+" 	c None",
+".	c #FFFFFF",
+"+	c #000000",
+"@	c #767676",
+"#	c #4E4E4E",
+"$	c #0C0C0C",
+"%	c #494949",
+"&	c #1B1B1B",
+"*	c #4D4D4D",
+"=	c #363636",
+"-	c #646464",
+";	c #515151",
+">	c #242424",
+",	c #585858",
+"'	c #545454",
+")	c #6A6A6A",
+"!	c #797979",
+"~	c #444444",
+"{	c #2E2E2E",
+"]	c #3B3B3B",
+"^	c #0A0A0A",
+"/	c #F7F7F7",
+"(	c #595959",
+"_	c #6B6B6B",
+":	c #080808",
+"<	c #FEFEFE",
+"[	c #FCFCFC",
+"}	c #FDFDFD",
+"..........     ",
+".++++++@.      ",
+".+++++#.       ",
+".++++$.        ",
+".+++++%.       ",
+".++&+++*.     .",
+".+=.-+++;.   ..",
+".>. .,+++'. .).",
+"..   .#+++,.!+.",
+".     .~+++{++.",
+"       .]+++++.",
+"        .^++++.",
+"       /(+++++.",
+"      /_::::::.",
+"     <[[[[[[[[}"};
diff --git a/common/fltk/src/fl_cursor_wait.xpm b/common/fltk/src/fl_cursor_wait.xpm
new file mode 100644
index 0000000..400d44d
--- /dev/null
+++ b/common/fltk/src/fl_cursor_wait.xpm
@@ -0,0 +1,72 @@
+/* XPM */
+static const char * fl_cursor_wait_xpm[] = {
+"17 32 37 1",
+" 	c None",
+".	c #FFFFFF",
+"+	c #2E2E2E",
+"@	c #202020",
+"#	c #F1F1F1",
+"$	c #2D2D2D",
+"%	c #000000",
+"&	c #EDEDED",
+"*	c #585858",
+"=	c #575757",
+"-	c #FBFBFB",
+";	c #848484",
+">	c #B8B8B8",
+",	c #E5E5E5",
+"'	c #F7F7F7",
+")	c #181818",
+"!	c #F0F0F0",
+"~	c #616161",
+"{	c #B7B7B7",
+"]	c #F5F5F5",
+"^	c #050505",
+"/	c #D4D4D4",
+"(	c #EEEEEE",
+"_	c #595959",
+":	c #7B7B7B",
+"<	c #E9E9E9",
+"[	c #131313",
+"}	c #E3E3E3",
+"|	c #767676",
+"1	c #505050",
+"2	c #F3F3F3",
+"3	c #2A2A2A",
+"4	c #070707",
+"5	c #343434",
+"6	c #939393",
+"7	c #191919",
+"8	c #6A6A6A",
+".................",
+".+@@@@@@@@@@@@@+.",
+".................",
+" #$%%%%%%%%%%%$# ",
+" &*%%%%%%%%%%%=& ",
+" -;%%%%%%%%%%%;- ",
+"  >%%%%%%%%%%%>  ",
+"  ,%%%%%%%%%%%,  ",
+"  ')%%%%%%%%%)'  ",
+"  !~%%%%%%%%%~!  ",
+"   {%%%%%%%%%{   ",
+"   ]^/...../^]   ",
+"   (_:.....:_(   ",
+"    <[}...}[<    ",
+"    !|1...1|!    ",
+"     2[3.3[2     ",
+"     2[%.%[2     ",
+"    !|%%.%%|!    ",
+"    <4%%.%%4<    ",
+"   (_%%%.%%%_(   ",
+"   ]^%%%.%%%^]   ",
+"   {%%%%.%%%%{   ",
+"  !~%%%%.%%%%~!  ",
+"  ')%%%%.%%%%)'  ",
+"  ,%%56{.{65%%,  ",
+"  >%*.......*%>  ",
+" -;7&.......&7;- ",
+" &*8.........8=& ",
+" #$%%%%%%%%%%%$# ",
+".................",
+".+@@@@@@@@@@@@@+.",
+"................."};
diff --git a/common/fltk/src/fl_draw_pixmap.cxx b/common/fltk/src/fl_draw_pixmap.cxx
index 68f7df6..b024485 100644
--- a/common/fltk/src/fl_draw_pixmap.cxx
+++ b/common/fltk/src/fl_draw_pixmap.cxx
@@ -67,99 +67,6 @@
   return 1;
 }
 
-#ifdef U64
-
-// The callback from fl_draw_image to get a row of data passes this:
-struct pixmap_data {
-  int w, h;
-  const uchar*const* data;
-  union {
-    U64 colors[256];
-    U64* byte1[256];
-  };
-};
-
-// callback for 1 byte per pixel:
-static void cb1(void*v, int x, int y, int w, uchar* buf) {
-  pixmap_data& d = *(pixmap_data*)v;
-  const uchar* p = d.data[y]+x;
-  U64* q = (U64*)buf;
-  for (int X=w; X>0; X-=2, p += 2) {
-    if (X>1) {
-#  if WORDS_BIGENDIAN
-      *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]];
-#  else
-      *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]];
-#  endif
-    } else {
-#  if WORDS_BIGENDIAN
-      *q++ = d.colors[p[0]]<<32;
-#  else
-      *q++ = d.colors[p[0]];
-#  endif
-    }
-  }
-}
-
-// callback for 2 bytes per pixel:
-static void cb2(void*v, int x, int y, int w, uchar* buf) {
-  pixmap_data& d = *(pixmap_data*)v;
-  const uchar* p = d.data[y]+2*x;
-  U64* q = (U64*)buf;
-  for (int X=w; X>0; X-=2) {
-    U64* colors = d.byte1[*p++];
-    int index = *p++;
-    if (X>1) {
-      U64* colors1 = d.byte1[*p++];
-      int index1 = *p++;
-#  if WORDS_BIGENDIAN
-      *q++ = (colors[index]<<32) | colors1[index1];
-#  else
-      *q++ = (colors1[index1]<<32) | colors[index];
-#  endif
-    } else {
-#  if WORDS_BIGENDIAN
-      *q++ = colors[index]<<32;
-#  else
-      *q++ = colors[index];
-#  endif
-    }
-  }
-}
-
-#else // U32
-
-// The callback from fl_draw_image to get a row of data passes this:
-struct pixmap_data {
-  int w, h;
-  const uchar*const* data;
-  union {
-    U32 colors[256];
-    U32* byte1[256];
-  };
-};
-
-// callback for 1 byte per pixel:
-static void cb1(void*v, int x, int y, int w, uchar* buf) {
-  pixmap_data& d = *(pixmap_data*)v;
-  const uchar* p = d.data[y]+x;
-  U32* q = (U32*)buf;
-  for (int X=w; X--;) *q++ = d.colors[*p++];
-}
-
-// callback for 2 bytes per pixel:
-static void cb2(void*v, int x, int y, int w, uchar* buf) {
-  pixmap_data& d = *(pixmap_data*)v;
-  const uchar* p = d.data[y]+2*x;
-  U32* q = (U32*)buf;
-  for (int X=w; X--;) {
-    U32* colors = d.byte1[*p++];
-    *q++ = colors[*p++];
-  }
-}
-
-#endif // U64 else U32
-
 uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here
 
 /**
@@ -209,34 +116,33 @@
 }
 #endif
 
-/**
-  Draw XPM image data, with the top-left corner at the given position.
-  \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
-  */
-int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
-  pixmap_data d;
-  if (!fl_measure_pixmap(cdata, d.w, d.h)) return 0;
+int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg) {
+  int w, h;
   const uchar*const* data = (const uchar*const*)(cdata+1);
   int transparent_index = -1;
   uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color
+
+  if (!fl_measure_pixmap(cdata, w, h))
+    return 0;
+
+  if ((chars_per_pixel < 1) || (chars_per_pixel > 2))
+    return 0;
+
+  uchar (*colors)[4] = new uchar [1<<(chars_per_pixel*8)][4];
+
 #ifdef WIN32
   color_count = 0;
   used_colors = (uchar *)malloc(abs(ncolors)*3*sizeof(uchar));
 #endif
 
-  if (ncolors < 0) {	// FLTK (non standard) compressed colormap
+  if (ncolors < 0) {
+    // FLTK (non standard) compressed colormap
     ncolors = -ncolors;
     const uchar *p = *data++;
     // if first color is ' ' it is transparent (put it later to make
     // it not be transparent):
     if (*p == ' ') {
-      uchar* c = (uchar*)&d.colors[(int)' '];
-#ifdef U64
-      *(U64*)c = 0;
-#  if WORDS_BIGENDIAN
-      c += 4;
-#  endif
-#endif
+      uchar* c = colors[(int)' '];
       transparent_index = ' ';
       Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
       transparent_c = c;
@@ -245,13 +151,7 @@
     }
     // read all the rest of the colors:
     for (int i=0; i < ncolors; i++) {
-      uchar* c = (uchar*)&d.colors[*p++];
-#ifdef U64
-      *(U64*)c = 0;
-#  if WORDS_BIGENDIAN
-      c += 4;
-#  endif
-#endif
+      uchar* c = colors[*p++];
 #ifdef WIN32
       used_colors[3*color_count] = *p;
       used_colors[3*color_count+1] = *(p+1);
@@ -261,75 +161,49 @@
       *c++ = *p++;
       *c++ = *p++;
       *c++ = *p++;
-#ifdef __APPLE_QUARTZ__
       *c = 255;
-#else
-      *c = 0;
-#endif
     }
-  } else {	// normal XPM colormap with names
-    if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1));
+  } else {
+    // normal XPM colormap with names
     for (int i=0; i<ncolors; i++) {
       const uchar *p = *data++;
       // the first 1 or 2 characters are the color index:
       int ind = *p++;
       uchar* c;
-      if (chars_per_pixel>1) {
-#ifdef U64
-	U64* colors = d.byte1[ind];
-	if (!colors) colors = d.byte1[ind] = new U64[256];
-#else
-	U32* colors = d.byte1[ind];
-	if (!colors) colors = d.byte1[ind] = new U32[256];
-#endif
-	c = (uchar*)&colors[*p];
-	ind = (ind<<8)|*p++;
-      } else {
-	c = (uchar *)&d.colors[ind];
-      }
+      if (chars_per_pixel>1)
+        ind = (ind<<8)|*p++;
+      c = colors[ind];
       // look for "c word", or last word if none:
       const uchar *previous_word = p;
       for (;;) {
-	while (*p && isspace(*p)) p++;
-	uchar what = *p++;
-	while (*p && !isspace(*p)) p++;
-	while (*p && isspace(*p)) p++;
-	if (!*p) {p = previous_word; break;}
-	if (what == 'c') break;
-	previous_word = p;
-	while (*p && !isspace(*p)) p++;
+        while (*p && isspace(*p)) p++;
+        uchar what = *p++;
+        while (*p && !isspace(*p)) p++;
+        while (*p && isspace(*p)) p++;
+        if (!*p) {p = previous_word; break;}
+        if (what == 'c') break;
+        previous_word = p;
+        while (*p && !isspace(*p)) p++;
       }
-#ifdef U64
-      *(U64*)c = 0;
-#  if WORDS_BIGENDIAN
-      c += 4;
-#  endif
-#endif
-#ifdef __APPLE_QUARTZ__
-      c[3] = 255;
-#endif
       int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]);
+      c[3] = 255;
       if (parse) {
 #ifdef WIN32
-	used_colors[3*color_count] = c[0];
-	used_colors[3*color_count+1] = c[1];
-	used_colors[3*color_count+2] = c[2];
-	color_count++;
+        used_colors[3*color_count] = c[0];
+        used_colors[3*color_count+1] = c[1];
+        used_colors[3*color_count+2] = c[2];
+        color_count++;
 #endif
-	}
-      else {
+      } else {
         // assume "None" or "#transparent" for any errors
-	// "bg" should be transparent...
-	Fl::get_color(bg, c[0], c[1], c[2]);
-#ifdef __APPLE_QUARTZ__
+        // "bg" should be transparent...
+        Fl::get_color(bg, c[0], c[1], c[2]);
         c[3] = 0;
-#endif
-	transparent_index = ind;
-	transparent_c = c;
+        transparent_index = ind;
+        transparent_c = c;
       }
     }
   }
-  d.data = data;
 #ifdef WIN32
   if (transparent_c) {
     make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]);
@@ -339,88 +213,89 @@
     make_unused_color(r, g, b);
   }
 #endif
-  
-#ifdef  __APPLE_QUARTZ__
-  if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
-    bool transparent = (transparent_index>=0);
-    transparent = true;
-    U32 *array = new U32[d.w * d.h], *q = array;
-    for (int Y = 0; Y < d.h; Y++) {
-      const uchar* p = data[Y];
-      if (chars_per_pixel <= 1) {
-	for (int X = 0; X < d.w; X++) {
-	  *q++ = d.colors[*p++];
-	}
-      } else {
-	for (int X = 0; X < d.w; X++) {
-	  U32* colors = (U32*)d.byte1[*p++];
-	  *q++ = colors[*p++];
-	}
+
+  U32 *q = (U32*)out;
+  for (int Y = 0; Y < h; Y++) {
+    const uchar* p = data[Y];
+    if (chars_per_pixel <= 1) {
+      for (int X = 0; X < w; X++)
+        memcpy(q++, colors[*p++], 4);
+    } else {
+      for (int X = 0; X < w; X++) {
+        int ind = (*p++)<<8;
+        ind |= *p++;
+        memcpy(q++, colors[ind], 4);
       }
     }
+  }
+  
+  delete [] colors;
+  return 1;
+}
+
+/**
+  Draw XPM image data, with the top-left corner at the given position.
+  \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
+  */
+int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
+  int w, h;
+
+  if (!fl_measure_pixmap(cdata, w, h))
+    return 0;
+
+  uchar *buffer = new uchar[w*h*4];
+
+  if (!fl_convert_pixmap(cdata, buffer, bg)) {
+    delete buffer;
+    return 0;
+  }
+
+  // FIXME: Hack until fl_draw_image() supports alpha properly
+#ifdef  __APPLE_QUARTZ__
+  if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
     CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
-    CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, d.w * d.h * 4, 0L);
-    CGImageRef img = CGImageCreate(d.w, d.h, 8, 4*8, 4*d.w,
-				   lut, transparent?kCGImageAlphaLast:kCGImageAlphaNoneSkipLast,
-				   src, 0L, false, kCGRenderingIntentDefault);
+    CGDataProviderRef src = CGDataProviderCreateWithData( 0L, buffer, w * h * 4, 0L);
+    CGImageRef img = CGImageCreate(w, h, 8, 4*8, 4*w,
+                                   lut, kCGImageAlphaLast,
+                                   src, 0L, false, kCGRenderingIntentDefault);
     CGColorSpaceRelease(lut);
     CGDataProviderRelease(src);
-    CGRect rect = { { x, y} , { d.w, d.h } };
-    Fl_X::q_begin_image(rect, 0, 0, d.w, d.h);
+    CGRect rect = { { x, y }, { w, h } };
+    Fl_X::q_begin_image(rect, 0, 0, w, h);
     CGContextDrawImage(fl_gc, rect, img);
     Fl_X::q_end_image();
     CGImageRelease(img);
-    delete[] array;
-    }
-  else {
+  } else {
 #endif // __APPLE_QUARTZ__
-
   // build the mask bitmap used by Fl_Pixmap:
-  if (fl_mask_bitmap && transparent_index >= 0) {
-    int W = (d.w+7)/8;
-    uchar* bitmap = new uchar[W * d.h];
+  if (fl_mask_bitmap) {
+    int W = (w+7)/8;
+    uchar* bitmap = new uchar[W * h];
     *fl_mask_bitmap = bitmap;
-    for (int Y = 0; Y < d.h; Y++) {
-      const uchar* p = data[Y];
-      if (chars_per_pixel <= 1) {
-	int dw = d.w;
-	for (int X = 0; X < W; X++) {
-	  uchar b = (dw-->0 && *p++ != transparent_index);
-	  if (dw-->0 && *p++ != transparent_index) b |= 2;
-	  if (dw-->0 && *p++ != transparent_index) b |= 4;
-	  if (dw-->0 && *p++ != transparent_index) b |= 8;
-	  if (dw-->0 && *p++ != transparent_index) b |= 16;
-	  if (dw-->0 && *p++ != transparent_index) b |= 32;
-	  if (dw-->0 && *p++ != transparent_index) b |= 64;
-	  if (dw-->0 && *p++ != transparent_index) b |= 128;
-	  *bitmap++ = b;
-	}
-      } else {
-        uchar b = 0, bit = 1;
-	for (int X = 0; X < d.w; X++) {
-	  int ind = *p++;
-	  ind = (ind<<8) | (*p++);
-	  if (ind != transparent_index) b |= bit;
-
-          if (bit < 128) bit <<= 1;
-	  else {
-	    *bitmap++ = b;
-	    b = 0;
-	    bit = 1;
-	  }
-	}
-
-        if (bit > 1) *bitmap++ = b;
+    const uchar *p = &buffer[3];
+    for (int Y = 0; Y < h; Y++) {
+      int dw = w;
+      for (int X = 0; X < W; X++) {
+        uchar b = 0;
+        for (int bit = 0x01;bit <= 0x80;bit<<=1) {
+          if (dw-- < 0)
+            break;
+          if (*p > 127)
+            b |= bit;
+          p += 4;
+        }
+        *bitmap++ = b;
       }
     }
   }
 
-  fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4);
+  fl_draw_image(buffer, x, y, w, h, 4);
+
 #ifdef __APPLE_QUARTZ__
     }
 #endif
 
-  if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i];
+  delete buffer;
   return 1;
 }
 
diff --git a/common/fltk/src/xutf8/imKStoUCS.c b/common/fltk/src/xutf8/imKStoUCS.c
index 0af9a80..802b005 100644
--- a/common/fltk/src/xutf8/imKStoUCS.c
+++ b/common/fltk/src/xutf8/imKStoUCS.c
@@ -266,6 +266,12 @@
     0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac                          /* 0x20a8-0x20af */
 };
 
+static unsigned short const keysym_to_unicode_fe50_fe60[] = {
+    0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0306, 0x0307, 0x0308, /* 0xfe50-0xfe57 */
+    0x030a, 0x030b, 0x030c, 0x0327, 0x0328, 0x1da5, 0x3099, 0x309a, /* 0xfe58-0xfe5f */
+    0x0323                                                          /* 0xfe60-0xfe67 */
+};
+
 unsigned int
 KeySymToUcs4(KeySym keysym)
 {
@@ -315,6 +321,8 @@
 	return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f];
     else if (keysym > 0x209f && keysym < 0x20ad)
 	return keysym_to_unicode_20a0_20ac[keysym - 0x20a0];
+    else if (keysym > 0xfe4f && keysym < 0xfe61)
+	return keysym_to_unicode_fe50_fe60[keysym - 0xfe50];
     else 
 	return 0;
 }