/* GDK - The GIMP Drawing Kit * Copyright (C) 2019 Руслан Ижбулатов * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "config.h" #define COBJMACROS #include #include #include "gdkprivate-win32.h" struct _GdkWin32ALPNSink { ITfActiveLanguageProfileNotifySink itf_alpn_sink; gint ref_count; }; typedef struct _GdkWin32ALPNSink GdkWin32ALPNSink; static GdkWin32ALPNSink *actlangchangenotify = NULL; static ITfSource *itf_source = NULL; static DWORD actlangchangenotify_id = 0; static ULONG STDMETHODCALLTYPE alpn_sink_addref (ITfActiveLanguageProfileNotifySink *This) { GdkWin32ALPNSink *alpn_sink = (GdkWin32ALPNSink *) This; int ref_count = ++alpn_sink->ref_count; return ref_count; } static HRESULT STDMETHODCALLTYPE alpn_sink_queryinterface (ITfActiveLanguageProfileNotifySink *This, REFIID riid, LPVOID *ppvObject) { *ppvObject = NULL; if (IsEqualGUID (riid, &IID_IUnknown)) { ITfActiveLanguageProfileNotifySink_AddRef (This); *ppvObject = This; return S_OK; } if (IsEqualGUID (riid, &IID_ITfActiveLanguageProfileNotifySink)) { ITfActiveLanguageProfileNotifySink_AddRef (This); *ppvObject = This; return S_OK; } return E_NOINTERFACE; } static ULONG STDMETHODCALLTYPE alpn_sink_release (ITfActiveLanguageProfileNotifySink *This) { GdkWin32ALPNSink *alpn_sink = (GdkWin32ALPNSink *) This; int ref_count = --alpn_sink->ref_count; if (ref_count == 0) { g_free (This); } return ref_count; } static HRESULT STDMETHODCALLTYPE alpn_sink_on_activated (ITfActiveLanguageProfileNotifySink *This, REFCLSID clsid, REFGUID guidProfile, BOOL fActivated) { _gdk_input_locale_is_ime = fActivated; return S_OK; } static ITfActiveLanguageProfileNotifySinkVtbl alpn_sink_vtbl = { alpn_sink_queryinterface, alpn_sink_addref, alpn_sink_release, alpn_sink_on_activated, }; static GdkWin32ALPNSink * alpn_sink_new () { GdkWin32ALPNSink *result; result = g_new0 (GdkWin32ALPNSink, 1); result->itf_alpn_sink.lpVtbl = &alpn_sink_vtbl; result->ref_count = 0; ITfActiveLanguageProfileNotifySink_AddRef (&result->itf_alpn_sink); return result; } void _gdk_win32_lang_notification_init () { HRESULT hr; ITfThreadMgr *itf_threadmgr; CoInitializeEx (NULL, COINIT_APARTMENTTHREADED); if (actlangchangenotify != NULL) return; hr = CoCreateInstance (&CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (LPVOID *) &itf_threadmgr); if (!SUCCEEDED (hr)) return; hr = ITfThreadMgr_QueryInterface (itf_threadmgr, &IID_ITfSource, (VOID **) &itf_source); ITfThreadMgr_Release (itf_threadmgr); if (!SUCCEEDED (hr)) return; actlangchangenotify = alpn_sink_new (); hr = ITfSource_AdviseSink (itf_source, &IID_ITfActiveLanguageProfileNotifySink, (IUnknown *) actlangchangenotify, &actlangchangenotify_id); if (!SUCCEEDED (hr)) { ITfActiveLanguageProfileNotifySink_Release (&actlangchangenotify->itf_alpn_sink); actlangchangenotify = NULL; ITfSource_Release (itf_source); itf_source = NULL; } } void _gdk_win32_lang_notification_exit () { if (actlangchangenotify != NULL && itf_source != NULL) { ITfSource_UnadviseSink (itf_source, actlangchangenotify_id); ITfSource_Release (itf_source); ITfActiveLanguageProfileNotifySink_Release (&actlangchangenotify->itf_alpn_sink); } CoUninitialize (); }