2019-11-23 20:27:39 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright (c) 2010-2012 cocos2d-x.org
|
|
|
|
Copyright (c) 2015 hanxi
|
|
|
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2022-10-01 16:24:52 +08:00
|
|
|
https://axmolengine.github.io/
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
2021-12-25 10:04:45 +08:00
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "ui/UIEditBox/UIEditBoxImpl-linux.h"
|
|
|
|
|
2022-07-16 10:43:05 +08:00
|
|
|
#if (AX_TARGET_PLATFORM == AX_PLATFORM_LINUX)
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
# include "ui/UIEditBox/UIEditBox.h"
|
2023-06-11 13:08:08 +08:00
|
|
|
# include "2d/Label.h"
|
|
|
|
# include "base/UTF8.h"
|
2023-11-19 09:38:12 +08:00
|
|
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
typedef char gchar;
|
|
|
|
typedef int gint;
|
|
|
|
typedef gint gboolean;
|
|
|
|
|
|
|
|
typedef unsigned long gulong;
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
G_CONNECT_DEFAULT = 0,
|
|
|
|
G_CONNECT_AFTER = 1 << 0,
|
|
|
|
G_CONNECT_SWAPPED = 1 << 1
|
|
|
|
} GConnectFlags;
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
GDK_WINDOW_TYPE_HINT_NORMAL,
|
|
|
|
GDK_WINDOW_TYPE_HINT_DIALOG,
|
|
|
|
GDK_WINDOW_TYPE_HINT_MENU, /* Torn off menu */
|
|
|
|
GDK_WINDOW_TYPE_HINT_TOOLBAR,
|
|
|
|
GDK_WINDOW_TYPE_HINT_SPLASHSCREEN,
|
|
|
|
GDK_WINDOW_TYPE_HINT_UTILITY,
|
|
|
|
GDK_WINDOW_TYPE_HINT_DOCK,
|
|
|
|
GDK_WINDOW_TYPE_HINT_DESKTOP,
|
|
|
|
GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU, /* A drop down menu (from a menubar) */
|
|
|
|
GDK_WINDOW_TYPE_HINT_POPUP_MENU, /* A popup menu (from right-click) */
|
|
|
|
GDK_WINDOW_TYPE_HINT_TOOLTIP,
|
|
|
|
GDK_WINDOW_TYPE_HINT_NOTIFICATION,
|
|
|
|
GDK_WINDOW_TYPE_HINT_COMBO,
|
|
|
|
GDK_WINDOW_TYPE_HINT_DND
|
|
|
|
} GdkWindowTypeHint;
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
GTK_WIN_POS_NONE,
|
|
|
|
GTK_WIN_POS_CENTER,
|
|
|
|
GTK_WIN_POS_MOUSE,
|
|
|
|
GTK_WIN_POS_CENTER_ALWAYS,
|
|
|
|
GTK_WIN_POS_CENTER_ON_PARENT
|
|
|
|
} GtkWindowPosition;
|
|
|
|
|
|
|
|
typedef struct _GtkAdjustment GtkAdjustment;
|
|
|
|
typedef struct _GtkBuilder GtkBuilder;
|
|
|
|
typedef struct _GtkClipboard GtkClipboard;
|
|
|
|
typedef struct _GtkIconSet GtkIconSet;
|
|
|
|
typedef struct _GtkIconSource GtkIconSource;
|
|
|
|
typedef struct _GtkRcStyle GtkRcStyle;
|
|
|
|
typedef struct _GtkRequisition GtkRequisition;
|
|
|
|
typedef struct _GtkSelectionData GtkSelectionData;
|
|
|
|
typedef struct _GtkSettings GtkSettings;
|
|
|
|
typedef struct _GtkStyle GtkStyle;
|
|
|
|
typedef struct _GtkStyleContext GtkStyleContext;
|
|
|
|
typedef struct _GtkTooltip GtkTooltip;
|
|
|
|
typedef struct _GtkWidget GtkWidget;
|
|
|
|
typedef struct _GtkWidgetPath GtkWidgetPath;
|
|
|
|
typedef struct _GtkWindow GtkWindow;
|
|
|
|
|
|
|
|
typedef struct _GtkDialog GtkDialog;
|
|
|
|
typedef struct _GtkDialogPrivate GtkDialogPrivate;
|
|
|
|
typedef struct _GtkDialogClass GtkDialogClass;
|
|
|
|
|
|
|
|
typedef struct _GTypeClass GTypeClass;
|
|
|
|
typedef struct _GTypeInstance GTypeInstance;
|
|
|
|
|
|
|
|
typedef void* gpointer;
|
|
|
|
|
|
|
|
typedef struct _GtkContainer GtkContainer;
|
|
|
|
|
|
|
|
typedef struct _GtkEntry GtkEntry;
|
|
|
|
|
|
|
|
typedef struct _GClosure GClosure;
|
|
|
|
|
|
|
|
typedef struct _GMainContext GMainContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
# if defined(__has_attribute) && __has_attribute(__const__)
|
|
|
|
# define G_GNUC_CONST __attribute__((__const__))
|
|
|
|
# else
|
|
|
|
# define G_GNUC_CONST
|
|
|
|
# endif
|
|
|
|
|
|
|
|
// dynamic load gtk-3 APIs
|
|
|
|
typedef unsigned long GType;
|
|
|
|
|
|
|
|
typedef void (*GCallback)(void);
|
|
|
|
typedef void (*GClosureNotify)(gpointer data, GClosure* closure);
|
|
|
|
|
|
|
|
#define G_CALLBACK(f) ((GCallback) (f))
|
|
|
|
|
|
|
|
static GType (*gtk_dialog_get_type)(void) G_GNUC_CONST;
|
|
|
|
static GType (*gtk_container_get_type)(void) G_GNUC_CONST;
|
|
|
|
static GType (*gtk_entry_get_type)(void) G_GNUC_CONST;
|
|
|
|
static GType (*gtk_window_get_type)(void) G_GNUC_CONST;
|
|
|
|
|
|
|
|
static void (*gtk_widget_destroy)(GtkWidget* widget);
|
|
|
|
static void (*gtk_init)(int* argc, char*** argv);
|
|
|
|
static GtkWidget* (*gtk_dialog_new)(void);
|
|
|
|
static GtkWidget* (*gtk_entry_new)(void);
|
|
|
|
static GtkWidget* (*gtk_dialog_get_content_area)(GtkDialog* dialog);
|
|
|
|
static void (*gtk_container_add)(GtkContainer* container, GtkWidget* widget);
|
|
|
|
static GtkWidget* (*gtk_dialog_add_button)(GtkDialog* dialog, const gchar* button_text, gint response_id);
|
|
|
|
static void (*gtk_entry_set_text)(GtkEntry* entry, const gchar* text);
|
|
|
|
static void (*gtk_window_set_keep_above)(GtkWindow* window, gboolean setting);
|
|
|
|
static gulong (*g_signal_connect_data)(gpointer instance,
|
|
|
|
const gchar* detailed_signal,
|
|
|
|
GCallback c_handler,
|
|
|
|
gpointer data,
|
|
|
|
GClosureNotify destroy_data,
|
|
|
|
GConnectFlags connect_flags);
|
|
|
|
static void (*gtk_window_set_type_hint)(GtkWindow* window, GdkWindowTypeHint hint);
|
|
|
|
static void (*gtk_window_set_position)(GtkWindow* window, GtkWindowPosition position);
|
|
|
|
static void (*gtk_widget_show_all)(GtkWidget* widget);
|
|
|
|
static gint (*gtk_dialog_run)(GtkDialog* dialog);
|
|
|
|
static const gchar* (*gtk_entry_get_text)(GtkEntry* entry);
|
|
|
|
static gboolean (*g_main_context_iteration)(GMainContext* context, gboolean may_block);
|
|
|
|
static GTypeInstance* (*g_type_check_instance_cast)(GTypeInstance* instance, GType iface_type);
|
|
|
|
|
|
|
|
/* --- implementation bits --- */
|
|
|
|
# if defined(G_DISABLE_CAST_CHECKS) || defined(__OPTIMIZE__)
|
|
|
|
# define _G_TYPE_CIC(ip, gt, ct) ((ct*)(void*)ip)
|
|
|
|
# define _G_TYPE_CCC(cp, gt, ct) ((ct*)(void*)cp)
|
|
|
|
# else
|
|
|
|
# define _G_TYPE_CIC(ip, gt, ct) ((ct*)(void*)g_type_check_instance_cast((GTypeInstance*)ip, gt))
|
|
|
|
# define _G_TYPE_CCC(cp, gt, ct) ((ct*)(void*)g_type_check_class_cast((GTypeClass*)cp, gt))
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_G_TYPE_CIC((instance), (g_type), c_type))
|
|
|
|
# define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_G_TYPE_CIC((instance), (g_type), c_type))
|
|
|
|
|
|
|
|
# define GTK_TYPE_DIALOG (gtk_dialog_get_type())
|
|
|
|
# define GTK_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_DIALOG, GtkDialog))
|
|
|
|
# define GTK_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_DIALOG, GtkDialogClass))
|
|
|
|
# define GTK_IS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_DIALOG))
|
|
|
|
# define GTK_IS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_DIALOG))
|
|
|
|
# define GTK_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_DIALOG, GtkDialogClass))
|
|
|
|
|
|
|
|
# define GTK_TYPE_CONTAINER (gtk_container_get_type())
|
|
|
|
# define GTK_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_CONTAINER, GtkContainer))
|
|
|
|
# define GTK_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_CONTAINER, GtkContainerClass))
|
|
|
|
# define GTK_IS_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_CONTAINER))
|
|
|
|
# define GTK_IS_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_CONTAINER))
|
|
|
|
# define GTK_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_CONTAINER, GtkContainerClass))
|
|
|
|
|
|
|
|
# define GTK_TYPE_ENTRY (gtk_entry_get_type())
|
|
|
|
# define GTK_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_ENTRY, GtkEntry))
|
|
|
|
# define GTK_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_ENTRY, GtkEntryClass))
|
|
|
|
# define GTK_IS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_ENTRY))
|
|
|
|
# define GTK_IS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_ENTRY))
|
|
|
|
# define GTK_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_ENTRY, GtkEntryClass))
|
|
|
|
|
|
|
|
# define GTK_TYPE_WINDOW (gtk_window_get_type())
|
|
|
|
# define GTK_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_WINDOW, GtkWindow))
|
|
|
|
# define GTK_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_WINDOW, GtkWindowClass))
|
|
|
|
# define GTK_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_WINDOW))
|
|
|
|
# define GTK_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_WINDOW))
|
|
|
|
# define GTK_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_WINDOW, GtkWindowClass))
|
|
|
|
|
|
|
|
# define g_signal_connect(instance, detailed_signal, c_handler, data) \
|
|
|
|
g_signal_connect_data((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags)0)
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
// destroy dialog when lost focus
|
|
|
|
static void dialogFocusOutCallback(GtkWidget* widget, gpointer user_data)
|
|
|
|
{
|
|
|
|
gtk_widget_destroy(widget);
|
|
|
|
}
|
|
|
|
|
2023-11-19 09:38:12 +08:00
|
|
|
#define GTK_DLSYM(func) do { \
|
|
|
|
func = reinterpret_cast<decltype(func)>(dlsym(gtk3, #func)); \
|
|
|
|
if (!func) throw std::runtime_error(#func); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
static bool load_gtk3() {
|
|
|
|
static bool s_loaded = false;
|
|
|
|
static void* gtk3 = 0;
|
|
|
|
|
|
|
|
if(!s_loaded) {
|
|
|
|
s_loaded = true;
|
|
|
|
|
|
|
|
gtk3 = dlopen("libgtk-3.so", RTLD_LAZY | RTLD_LOCAL);
|
|
|
|
if(gtk3) {
|
|
|
|
try {
|
|
|
|
GTK_DLSYM(gtk_dialog_get_type);
|
|
|
|
GTK_DLSYM(gtk_container_get_type);
|
|
|
|
GTK_DLSYM(gtk_entry_get_type);
|
|
|
|
GTK_DLSYM(gtk_window_get_type);
|
|
|
|
GTK_DLSYM(gtk_widget_destroy);
|
|
|
|
GTK_DLSYM(gtk_init);
|
|
|
|
GTK_DLSYM(gtk_dialog_new);
|
|
|
|
GTK_DLSYM(gtk_entry_new);
|
|
|
|
GTK_DLSYM(gtk_dialog_get_content_area);
|
|
|
|
GTK_DLSYM(gtk_container_add);
|
|
|
|
GTK_DLSYM(gtk_dialog_add_button);
|
|
|
|
GTK_DLSYM(gtk_entry_set_text);
|
|
|
|
GTK_DLSYM(gtk_window_set_keep_above);
|
|
|
|
GTK_DLSYM(g_signal_connect_data);
|
|
|
|
GTK_DLSYM(gtk_window_set_type_hint);
|
|
|
|
GTK_DLSYM(gtk_window_set_position);
|
|
|
|
GTK_DLSYM(gtk_widget_show_all);
|
|
|
|
GTK_DLSYM(gtk_dialog_run);
|
|
|
|
GTK_DLSYM(gtk_entry_get_text);
|
|
|
|
GTK_DLSYM(g_main_context_iteration);
|
|
|
|
GTK_DLSYM(g_type_check_instance_cast);
|
|
|
|
} catch(const std::exception& ex) {
|
2024-03-07 08:47:00 +08:00
|
|
|
AXLOGE("load gtk function: {} fail", ex.what());
|
2023-11-19 09:38:12 +08:00
|
|
|
dlclose(gtk3);
|
|
|
|
gtk3 = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return !!gtk3;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool LinuxInputBox(std::string& entryLine)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
2023-11-19 09:38:12 +08:00
|
|
|
if(!load_gtk3()) {
|
|
|
|
throw std::runtime_error("missing library gtk3");
|
|
|
|
}
|
|
|
|
|
2019-11-23 20:27:39 +08:00
|
|
|
bool didChange = false;
|
2021-12-25 10:04:45 +08:00
|
|
|
GtkWidget* dialog;
|
|
|
|
GtkWidget* entry;
|
|
|
|
GtkWidget* contentArea;
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
gtk_init(0, NULL);
|
2021-12-25 10:04:45 +08:00
|
|
|
dialog = gtk_dialog_new();
|
|
|
|
entry = gtk_entry_new();
|
2019-11-23 20:27:39 +08:00
|
|
|
contentArea = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
|
|
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(contentArea), entry);
|
|
|
|
gtk_dialog_add_button(GTK_DIALOG(dialog), "OK", 0);
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(entry), entryLine.c_str());
|
|
|
|
|
|
|
|
g_signal_connect(dialog, "focus-out-event", G_CALLBACK(dialogFocusOutCallback), NULL);
|
|
|
|
gtk_window_set_keep_above(GTK_WINDOW(dialog), true);
|
|
|
|
gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_MENU);
|
|
|
|
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
|
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
|
|
|
|
gint result = gtk_dialog_run(GTK_DIALOG(dialog));
|
2021-12-25 10:04:45 +08:00
|
|
|
switch (result)
|
2019-11-23 20:27:39 +08:00
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
entryLine = gtk_entry_get_text(GTK_ENTRY(entry));
|
|
|
|
didChange = true;
|
|
|
|
break;
|
|
|
|
default:
|
2022-07-16 10:43:05 +08:00
|
|
|
// AXLOG("Undefined. Perhaps dialog was closed");
|
2019-11-23 20:27:39 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_widget_destroy(dialog);
|
2021-12-25 10:04:45 +08:00
|
|
|
while (g_main_context_iteration(NULL, false))
|
|
|
|
;
|
2019-11-23 20:27:39 +08:00
|
|
|
return didChange;
|
|
|
|
}
|
|
|
|
|
2022-07-11 17:50:21 +08:00
|
|
|
NS_AX_BEGIN
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
namespace ui
|
|
|
|
{
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
EditBoxImpl* __createSystemEditBox(EditBox* pEditBox)
|
|
|
|
{
|
|
|
|
return new EditBoxImplLinux(pEditBox);
|
|
|
|
}
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
EditBoxImplLinux::EditBoxImplLinux(EditBox* pEditText) : EditBoxImplCommon(pEditText) {}
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
EditBoxImplLinux::~EditBoxImplLinux() {}
|
2019-11-23 20:27:39 +08:00
|
|
|
|
|
|
|
bool EditBoxImplLinux::isEditing()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditBoxImplLinux::nativeOpenKeyboard()
|
|
|
|
{
|
|
|
|
std::string text = this->getText();
|
2021-12-25 10:04:45 +08:00
|
|
|
bool didChange = LinuxInputBox(text);
|
2019-11-23 20:27:39 +08:00
|
|
|
if (didChange)
|
|
|
|
{
|
|
|
|
this->editBoxEditingDidEnd(text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-25 10:04:45 +08:00
|
|
|
} // namespace ui
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2022-07-11 17:50:21 +08:00
|
|
|
NS_AX_END
|
2019-11-23 20:27:39 +08:00
|
|
|
|
2022-07-16 10:43:05 +08:00
|
|
|
#endif /* #if (AX_TARGET_PLATFORM == AX_PLATFORM_LINUX) */
|