diff -up fltk-1.3.2/FL/Fl.H.im fltk-1.3.2/FL/Fl.H --- fltk-1.3.2/FL/Fl.H.im 2014-09-10 14:40:05.193265424 +0200 +++ fltk-1.3.2/FL/Fl.H 2014-09-10 14:40:05.196265471 +0200 @@ -699,6 +699,17 @@ public: static int event_inside(const Fl_Widget*); static int test_shortcut(Fl_Shortcut); + /** + Enables the system input methods facilities. This is the default. + \see disable_im() + */ + static void enable_im(); + /** + Disables the system input methods facilities. + \see enable_im() + */ + static void disable_im(); + // event destinations: static int handle(int, Fl_Window*); static int handle_(int, Fl_Window*); diff -up fltk-1.3.2/FL/win32.H.im fltk-1.3.2/FL/win32.H --- fltk-1.3.2/FL/win32.H.im 2014-09-10 14:40:05.186265315 +0200 +++ fltk-1.3.2/FL/win32.H 2014-09-10 14:40:05.196265471 +0200 @@ -102,6 +102,8 @@ extern FL_EXPORT void fl_save_dc( HWND w inline Window fl_xid(const Fl_Window* w) { Fl_X *temp = Fl_X::i(w); return temp ? temp->xid : 0; } +extern FL_EXPORT void fl_open_display(); + #else FL_EXPORT Window fl_xid_(const Fl_Window* w); #define fl_xid(w) fl_xid_(w) diff -up fltk-1.3.2/src/Fl_cocoa.mm.im fltk-1.3.2/src/Fl_cocoa.mm --- fltk-1.3.2/src/Fl_cocoa.mm.im 2014-09-10 14:40:05.193265424 +0200 +++ fltk-1.3.2/src/Fl_cocoa.mm 2014-09-10 14:43:41.103642243 +0200 @@ -88,6 +88,7 @@ static void createAppleMenu(void); static Fl_Region MacRegionMinusRect(Fl_Region r, int x,int y,int w,int h); static void cocoaMouseHandler(NSEvent *theEvent); static int calc_mac_os_version(); +static void im_update(void); static Fl_Quartz_Graphics_Driver fl_quartz_driver; static Fl_Display_Device fl_quartz_display(&fl_quartz_driver); @@ -108,6 +109,30 @@ int fl_mac_os_version = calc_mac_os_vers static int got_events = 0; static Fl_Window* resize_from_system; static int main_screen_height; // height of menubar-containing screen used to convert between Cocoa and FLTK global screen coordinates +static int im_enabled = -1; + +// Carbon functions and definitions + +typedef void *TSMDocumentID; + +extern "C" enum { + kTSMDocumentEnabledInputSourcesPropertyTag = 'enis' // from Carbon/TextServices.h +}; + +// Undocumented voodoo. Taken from Mozilla. +static const int smEnableRomanKybdsOnly = -23; + +typedef TSMDocumentID (*TSMGetActiveDocument_type)(void); +static TSMGetActiveDocument_type TSMGetActiveDocument; +typedef OSStatus (*TSMSetDocumentProperty_type)(TSMDocumentID, OSType, UInt32, void*); +static TSMSetDocumentProperty_type TSMSetDocumentProperty; +typedef OSStatus (*TSMRemoveDocumentProperty_type)(TSMDocumentID, OSType); +static TSMRemoveDocumentProperty_type TSMRemoveDocumentProperty; +typedef CFArrayRef (*TISCreateASCIICapableInputSourceList_type)(void); +static TISCreateASCIICapableInputSourceList_type TISCreateASCIICapableInputSourceList; + +typedef void (*KeyScript_type)(short); +static KeyScript_type KeyScript; #if CONSOLIDATE_MOTION static Fl_Window* send_motion; @@ -978,6 +1003,7 @@ void fl_open_callback(void (*cb)(const c #endif { BOOL seen_open_file; + TSMDocumentID currentDoc; } - (void)windowDidMove:(NSNotification *)notif; - (void)windowDidResize:(NSNotification *)notif; @@ -991,6 +1017,7 @@ void fl_open_callback(void (*cb)(const c - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender; - (void)applicationDidBecomeActive:(NSNotification *)notify; - (void)applicationDidChangeScreenParameters:(NSNotification *)aNotification; +- (void)applicationDidUpdate:(NSNotification *)aNotification; - (void)applicationWillResignActive:(NSNotification *)notify; - (void)applicationWillHide:(NSNotification *)notify; - (void)applicationWillUnhide:(NSNotification *)notify; @@ -1175,6 +1202,23 @@ void fl_open_callback(void (*cb)(const c } Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL); } +- (void)applicationDidUpdate:(NSNotification *)aNotification +{ + if ((fl_mac_os_version >= 100500) && (im_enabled != -1) && + (TSMGetActiveDocument != NULL)) { + TSMDocumentID newDoc; + // It is extremely unclear when Cocoa decides to create/update + // the input context, but debugging reveals that it is done + // by NSApplication:updateWindows. So check if the input context + // has shifted after each such run so that we can update our + // input methods status. + newDoc = TSMGetActiveDocument(); + if (newDoc != currentDoc) { + im_update(); + currentDoc = newDoc; + } + } +} - (void)applicationWillResignActive:(NSNotification *)notify { fl_lock_function(); @@ -1322,6 +1365,13 @@ void fl_open_display() { static char beenHereDoneThat = 0; if ( !beenHereDoneThat ) { beenHereDoneThat = 1; + + TSMGetActiveDocument = (TSMGetActiveDocument_type)Fl_X::get_carbon_function("TSMGetActiveDocument"); + TSMSetDocumentProperty = (TSMSetDocumentProperty_type)Fl_X::get_carbon_function("TSMSetDocumentProperty"); + TSMRemoveDocumentProperty = (TSMRemoveDocumentProperty_type)Fl_X::get_carbon_function("TSMRemoveDocumentProperty"); + TISCreateASCIICapableInputSourceList = (TISCreateASCIICapableInputSourceList_type)Fl_X::get_carbon_function("TISCreateASCIICapableInputSourceList"); + + KeyScript = (KeyScript_type)Fl_X::get_carbon_function("KeyScript"); BOOL need_new_nsapp = (NSApp == nil); if (need_new_nsapp) [NSApplication sharedApplication]; @@ -1390,6 +1440,66 @@ void fl_open_display() { void fl_close_display() { } +// 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... + +static void im_update(void) { + if (fl_mac_os_version >= 100500) { + TSMDocumentID doc; + + if ((TSMGetActiveDocument == NULL) || + (TSMSetDocumentProperty == NULL) || + (TSMRemoveDocumentProperty == NULL) || + (TISCreateASCIICapableInputSourceList == NULL)) + return; + + doc = TSMGetActiveDocument(); + + if (im_enabled) + TSMRemoveDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag); + else { + CFArrayRef inputSources; + + inputSources = TISCreateASCIICapableInputSourceList(); + TSMSetDocumentProperty(doc, kTSMDocumentEnabledInputSourcesPropertyTag, + sizeof(CFArrayRef), &inputSources); + CFRelease(inputSources); + } + } else { + if (KeyScript == NULL) + return; + + if (im_enabled) + KeyScript(smKeyEnableKybds); + else + KeyScript(smEnableRomanKybdsOnly); + } +} + +void Fl::enable_im() { + fl_open_display(); + + im_enabled = 1; + + if (fl_mac_os_version >= 100500) + [NSApp updateWindows]; + else + im_update(); +} + +void Fl::disable_im() { + fl_open_display(); + + im_enabled = 0; + + if (fl_mac_os_version >= 100500) + [NSApp updateWindows]; + else + im_update(); +} + // Gets the border sizes and the titlebar size static void get_window_frame_sizes(int &bx, int &by, int &bt) { diff -up fltk-1.3.2/src/Fl.cxx.im fltk-1.3.2/src/Fl.cxx --- fltk-1.3.2/src/Fl.cxx.im 2014-09-10 14:40:05.194265440 +0200 +++ fltk-1.3.2/src/Fl.cxx 2014-09-10 14:40:05.197265486 +0200 @@ -593,45 +593,6 @@ int Fl::run() { return 0; } -#ifdef WIN32 - -// Function to initialize COM/OLE for usage. This must be done only once. -// We define a flag to register whether we called it: -static char oleInitialized = 0; - -// This calls the Windows function OleInitialize() exactly once. -void fl_OleInitialize() { - if (!oleInitialized) { - OleInitialize(0L); - oleInitialized = 1; - } -} - -// This calls the Windows function OleUninitialize() only, if -// OleInitialize has been called before. -void fl_OleUninitialize() { - if (oleInitialized) { - OleUninitialize(); - oleInitialized = 0; - } -} - -class Fl_Win32_At_Exit { -public: - Fl_Win32_At_Exit() { } - ~Fl_Win32_At_Exit() { - fl_free_fonts(); // do some WIN32 cleanup - fl_cleanup_pens(); - fl_OleUninitialize(); - fl_brush_action(1); - fl_cleanup_dc_list(); - } -}; -static Fl_Win32_At_Exit win32_at_exit; -#endif - - - /** Waits until "something happens" and then returns. Call this repeatedly to "run" your program. You can also check what happened diff -up fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx --- fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx.im 2012-06-26 09:03:46.000000000 +0200 +++ fltk-1.3.2/src/Fl_Native_File_Chooser_WIN32.cxx 2014-09-10 14:40:05.197265486 +0200 @@ -34,6 +34,7 @@ LPCWSTR utf8towchar(const char *in); //M char *wchartoutf8(LPCWSTR in); //MG #include +#include #define LCURLY_CHR '{' #define RCURLY_CHR '}' @@ -41,8 +42,6 @@ char *wchartoutf8(LPCWSTR in); //MG #define RBRACKET_CHR ']' #define MAXFILTERS 80 -void fl_OleInitialize(); // in Fl.cxx (Windows only) - // STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG) #ifdef DEBUG static void dnullprint(char *wp) { @@ -471,7 +470,7 @@ int CALLBACK Fl_Native_File_Chooser::Dir // SHOW DIRECTORY BROWSER int Fl_Native_File_Chooser::showdir() { // initialize OLE only once - fl_OleInitialize(); // init needed by BIF_USENEWUI + fl_open_display(); // init needed by BIF_USENEWUI ClearBINF(); clear_pathnames(); // PARENT WINDOW diff -up fltk-1.3.2/src/Fl_win32.cxx.im fltk-1.3.2/src/Fl_win32.cxx --- fltk-1.3.2/src/Fl_win32.cxx.im 2014-09-10 14:40:05.194265440 +0200 +++ fltk-1.3.2/src/Fl_win32.cxx 2014-09-10 14:40:05.197265486 +0200 @@ -60,8 +60,6 @@ #include #include -#include "aimm.h" - // // USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()... // USE_ASYNC_SELECT is OBSOLETED in 1.3 for the following reasons: @@ -121,27 +119,24 @@ static HMODULE get_wsock_mod() { * 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); static flTypeImmSetCompositionWindow flImmSetCompositionWindow = 0; typedef BOOL (WINAPI* flTypeImmReleaseContext)(HWND, HIMC); static flTypeImmReleaseContext flImmReleaseContext = 0; -typedef BOOL (WINAPI* flTypeImmIsIME)(HKL); -static flTypeImmIsIME flImmIsIME = 0; -static HMODULE get_imm_module() { - if (!s_imm_module) { - s_imm_module = LoadLibrary("IMM32.DLL"); - if (!s_imm_module) - Fl::fatal("FLTK Lib Error: IMM32.DLL file not found!\n\n" - "Please check your input method manager library accessibility."); - flImmGetContext = (flTypeImmGetContext)GetProcAddress(s_imm_module, "ImmGetContext"); - flImmSetCompositionWindow = (flTypeImmSetCompositionWindow)GetProcAddress(s_imm_module, "ImmSetCompositionWindow"); - flImmReleaseContext = (flTypeImmReleaseContext)GetProcAddress(s_imm_module, "ImmReleaseContext"); - flImmIsIME = (flTypeImmIsIME)GetProcAddress(s_imm_module, "ImmIsIME"); - } - return s_imm_module; +static void get_imm_module() { + s_imm_module = LoadLibrary("IMM32.DLL"); + 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"); } // USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have @@ -259,7 +254,9 @@ void fl_set_spot(int font, int size, int Fl_Window* tw = win; while (tw->parent()) tw = tw->window(); // find top level window - get_imm_module(); + if (!tw->shown()) + return; + HIMC himc = flImmGetContext(fl_xid(tw)); if (himc) { @@ -338,7 +335,6 @@ void* Fl::thread_message() { extern int fl_send_system_handlers(void *e); -IActiveIMMApp *fl_aimm = NULL; MSG fl_msg; // This is never called with time_to_wait < 0.0. @@ -441,6 +437,58 @@ int fl_ready() { return get_wsock_mod() ? s_wsock_select(0,&fdt[0],&fdt[1],&fdt[2],&t) : 0; } +void fl_open_display() { + static char beenHereDoneThat = 0; + + if (beenHereDoneThat) + return; + + beenHereDoneThat = 1; + + OleInitialize(0L); + + get_imm_module(); +} + +class Fl_Win32_At_Exit { +public: + Fl_Win32_At_Exit() { } + ~Fl_Win32_At_Exit() { + fl_free_fonts(); // do some WIN32 cleanup + fl_cleanup_pens(); + OleUninitialize(); + fl_brush_action(1); + fl_cleanup_dc_list(); + } +}; +static Fl_Win32_At_Exit win32_at_exit; + +static char im_enabled = 1; + +void Fl::enable_im() { + fl_open_display(); + + Fl_X* i = Fl_X::first; + while (i) { + flImmAssociateContextEx(i->xid, 0, IACE_DEFAULT); + i = i->next; + } + + im_enabled = 1; +} + +void Fl::disable_im() { + fl_open_display(); + + Fl_X* i = Fl_X::first; + while (i) { + flImmAssociateContextEx(i->xid, 0, 0); + i = i->next; + } + + im_enabled = 0; +} + //////////////////////////////////////////////////////////////// int Fl::x() @@ -683,7 +731,6 @@ void fl_clipboard_notify_untarget(HWND w } //////////////////////////////////////////////////////////////// -char fl_is_ime = 0; void fl_get_codepage() { HKL hkl = GetKeyboardLayout(0); @@ -691,14 +738,8 @@ void fl_get_codepage() GetLocaleInfo (LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE, ld, 6); DWORD ccp = atol(ld); - fl_is_ime = 0; fl_codepage = ccp; - if (fl_aimm) { - fl_aimm->GetCodePageA(GetKeyboardLayout(0), &fl_codepage); - } else if (get_imm_module() && flImmIsIME(hkl)) { - fl_is_ime = 1; - } } HWND fl_capture; @@ -1564,6 +1605,8 @@ int fl_disable_transient_for; // secret Fl_X* Fl_X::make(Fl_Window* w) { Fl_Group::current(0); // get rid of very common user bug: forgot end() + fl_open_display(); + // if the window is a subwindow and our parent is not mapped yet, we // mark this window visible, so that mapping the parent at a later // point in time will call this function again to finally map the subwindow. @@ -1767,16 +1810,10 @@ Fl_X* Fl_X::make(Fl_Window* w) { (Fl::grab() || (styleEx & WS_EX_TOOLWINDOW)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); // Register all windows for potential drag'n'drop operations - fl_OleInitialize(); RegisterDragDrop(x->xid, flIDropTarget); - if (!fl_aimm) { - CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_INPROC_SERVER, - IID_IActiveIMMApp, (void**) &fl_aimm); - if (fl_aimm) { - fl_aimm->Activate(TRUE); - } - } + if (!im_enabled) + flImmAssociateContextEx(x->xid, 0, 0); return x; } diff -up fltk-1.3.2/src/Fl_x.cxx.im fltk-1.3.2/src/Fl_x.cxx --- fltk-1.3.2/src/Fl_x.cxx.im 2014-09-10 14:40:05.194265440 +0200 +++ fltk-1.3.2/src/Fl_x.cxx 2014-09-10 14:40:05.198265502 +0200 @@ -313,6 +313,7 @@ XVisualInfo *fl_visual; 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; @@ -603,6 +604,55 @@ void fl_init_xim() { 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; +} + +void Fl::enable_im() { + Fl_Window *win; + + win = Fl::first_window(); + if (win && win->shown()) { + fl_xim_activate(fl_xid(win)); + XSetICFocus(fl_xim_ic); + } else { + fl_new_ic(); + } +} + +void Fl::disable_im() { + fl_xim_deactivate(); +} + void fl_open_display() { if (fl_display) return; @@ -1053,10 +1103,9 @@ int fl_handle(const XEvent& thisevent) 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); @@ -1072,46 +1121,9 @@ int fl_handle(const XEvent& thisevent) } 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 - } + fl_xim_activate(xid); - if ( XFilterEvent((XEvent *)&xevent, 0) ) + if (fl_xim_ic && XFilterEvent((XEvent *)&xevent, 0)) return(1); #if USE_XRANDR