mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
This might bring some incompatibilities in the code that expects wchar to be 16 bit, which escpecially involves dealing with Win32 (and to lesser extend MacOS) APIs, so if your application is doing that, please check all instances of WCHAR (UniChar on MacOS) or even wchar especially type casts. To support host APIs, char16 is introduced (but there is no 16-bit String varian). Use ToSystemCharsetW, FromSystemCharsetW to convert texts to Win32 API. - Support of drawing non-BMP characters in GUI - Vastly improved character font replacement code (when drawing characters missing with requested font, replacement font is used) - Last instances of Win32 ANSI calls (those ending with A) are removed - UTF handling routines are refactored and their's naming is unified - RTF is now being able to handle non-BMP characters (RTF is used as clipboard format for RichText) Other minor changes: - fixed TryRealloc issue - improved MemoryCheck - Removed MemoryAlloc48/MemoryFree48 - In theide Background parsing should less often cause delays in the main thread
417 lines
9.2 KiB
C++
417 lines
9.2 KiB
C++
#include <CtrlCore/CtrlCore.h>
|
|
#include <plugin/bmp/bmp.h>
|
|
|
|
#ifdef GUI_GTK
|
|
|
|
namespace Upp {
|
|
|
|
#define LLOG(x) // DLOG(x)
|
|
|
|
void Ctrl::GtkSelectionDataSet(GtkSelectionData *selection_data, const String& fmt, const String& data)
|
|
{
|
|
if(fmt == "files") {
|
|
Vector<String> h = Split(data, '\n');
|
|
Buffer<gchar *> uris(h.GetCount() + 1, NULL);
|
|
for(int i = 0; i < h.GetCount(); i++) {
|
|
int l = h[i].GetCount() + 1;
|
|
uris[i] = new gchar[l];
|
|
memcpy(uris[i], ~h[i], l);
|
|
}
|
|
gtk_selection_data_set_uris(selection_data, ~uris);
|
|
for(int i = 0; i < h.GetCount(); i++)
|
|
delete uris[i];
|
|
}
|
|
else
|
|
if(fmt == "text")
|
|
gtk_selection_data_set_text(selection_data, (const gchar*)~data, data.GetCount());
|
|
else
|
|
if(fmt == "image") {
|
|
Image img;
|
|
if(IsString(data))
|
|
LoadFromString(img, data);
|
|
if(!IsNull(img)) {
|
|
ImageGdk m(img);
|
|
gtk_selection_data_set_pixbuf(selection_data, m);
|
|
}
|
|
}
|
|
else
|
|
gtk_selection_data_set(selection_data, GAtom(fmt), 8, (const guchar*)~data, data.GetCount());
|
|
}
|
|
|
|
void Ctrl::GtkGetClipData(GtkClipboard *clipboard, GtkSelectionData *selection_data,
|
|
guint info, gpointer user_data)
|
|
{
|
|
VectorMap<String, ClipData>& target = ((Gclipboard *)user_data)->target;
|
|
LLOG("GtkGetClipData for " << target.GetKey(info));
|
|
GtkSelectionDataSet(selection_data, target.GetKey(info), target[info].Render());
|
|
}
|
|
|
|
void ClearClipData(GtkClipboard *clipboard, gpointer) {}
|
|
|
|
Ctrl::Gclipboard::Gclipboard(GdkAtom type)
|
|
{
|
|
clipboard = gtk_clipboard_get(type);
|
|
}
|
|
|
|
void Ctrl::AddFmt(GtkTargetList *list, const String& fmt, int info)
|
|
{
|
|
if(fmt == "files")
|
|
gtk_target_list_add_uri_targets(list, info);
|
|
else
|
|
if(fmt == "text")
|
|
gtk_target_list_add_text_targets(list, info);
|
|
else
|
|
if(fmt == "image")
|
|
gtk_target_list_add_image_targets(list, info, TRUE);
|
|
else
|
|
gtk_target_list_add(list, GAtom(fmt), 0, info);
|
|
}
|
|
|
|
GtkTargetList *Ctrl::CreateTargetList(const VectorMap<String, ClipData>& target)
|
|
{
|
|
GtkTargetList *list = gtk_target_list_new(NULL, 0);
|
|
for(int i = 0; i < target.GetCount(); i++)
|
|
AddFmt(list, target.GetKey(i), i);
|
|
return list;
|
|
}
|
|
|
|
void Ctrl::Gclipboard::Put(const String& fmt, const ClipData& data)
|
|
{
|
|
GuiLock __;
|
|
LLOG("Gclipboard::Put " << fmt);
|
|
|
|
target.GetAdd(fmt) = data;
|
|
|
|
GtkTargetList *list = CreateTargetList(target);
|
|
|
|
gint n;
|
|
GtkTargetEntry *targets = gtk_target_table_new_from_list(list, &n);
|
|
|
|
gtk_clipboard_set_with_data(clipboard, targets, n, GtkGetClipData, ClearClipData, this);
|
|
gtk_clipboard_set_can_store(clipboard, NULL, 0);
|
|
|
|
gtk_target_table_free(targets, n);
|
|
gtk_target_list_unref(list);
|
|
}
|
|
|
|
String Ctrl::GtkDataGet(GtkSelectionData *s)
|
|
{
|
|
if(!s)
|
|
return Null;
|
|
const guchar *b = gtk_selection_data_get_data(s);
|
|
int n = gtk_selection_data_get_length(s);
|
|
return n >= 0 && b ? String(b, n) : String();
|
|
}
|
|
|
|
String Ctrl::Gclipboard::Get(const String& fmt)
|
|
{
|
|
LLOG("Ctrl::Gclipboard::Get " << fmt);
|
|
if(fmt == "text") {
|
|
gchar *s = gtk_clipboard_wait_for_text(clipboard);
|
|
if(s) {
|
|
String h = s;
|
|
g_free(s);
|
|
return h;
|
|
}
|
|
return Null;
|
|
}
|
|
else
|
|
if(fmt == "image")
|
|
return ImageClipFromPixbufUnref(gtk_clipboard_wait_for_image(clipboard));
|
|
else
|
|
if(fmt == "files")
|
|
return FilesClipFromUrisFree(gtk_clipboard_wait_for_uris(clipboard));
|
|
else
|
|
return GtkDataGet(gtk_clipboard_wait_for_contents(clipboard, GAtom(fmt)));
|
|
}
|
|
|
|
bool Ctrl::Gclipboard::IsAvailable(const String& fmt)
|
|
{
|
|
if(fmt == "files")
|
|
return gtk_clipboard_wait_is_uris_available(clipboard);
|
|
if(fmt == "text")
|
|
return gtk_clipboard_wait_is_text_available(clipboard);
|
|
if(fmt == "image")
|
|
return gtk_clipboard_wait_is_image_available(clipboard);
|
|
return gtk_clipboard_wait_is_target_available(clipboard, GAtom(fmt));
|
|
}
|
|
|
|
bool PasteClip::IsAvailable(const char *fmt) const
|
|
{
|
|
LLOG("PasteClip::IsAvailable " << fmt << ", type: " << type);
|
|
if(type == 1)
|
|
return Ctrl::IsDragAvailable(fmt);
|
|
return (type == 0 ? Ctrl::gclipboard() : Ctrl::gselection()).IsAvailable(fmt);
|
|
}
|
|
|
|
String PasteClip::Get(const char *fmt) const
|
|
{
|
|
LLOG("PasteClip::Get " << fmt << ", type: " << type);
|
|
if(type == 1)
|
|
return Ctrl::DragGet(fmt);
|
|
return (type == 0 ? Ctrl::gclipboard() : Ctrl::gselection()).Get(fmt);
|
|
}
|
|
|
|
void PasteClip::GuiPlatformConstruct()
|
|
{
|
|
type = 0;
|
|
}
|
|
|
|
void Ctrl::Gclipboard::Clear()
|
|
{
|
|
gtk_clipboard_clear(clipboard);
|
|
target.Clear();
|
|
}
|
|
|
|
void ClearClipboard()
|
|
{
|
|
Ctrl::gclipboard().Clear();
|
|
}
|
|
|
|
Ctrl::Gclipboard& Ctrl::gclipboard()
|
|
{
|
|
GuiLock __;
|
|
static Gclipboard c(GDK_SELECTION_CLIPBOARD);
|
|
return c;
|
|
}
|
|
|
|
Ctrl::Gclipboard& Ctrl::gselection()
|
|
{
|
|
GuiLock __;
|
|
static Gclipboard c(GDK_SELECTION_PRIMARY);
|
|
return c;
|
|
}
|
|
|
|
void AppendClipboard(const char *format, const Value& data, String (*render)(const Value& data))
|
|
{
|
|
GuiLock __;
|
|
LLOG("AppendClipboard " << format);
|
|
Vector<String> s = Split(format, ';');
|
|
for(int i = 0; i < s.GetCount(); i++)
|
|
Ctrl::gclipboard().Put(s[i], ClipData(data, render));
|
|
}
|
|
|
|
void AppendClipboard(const char *format, const byte *data, int length)
|
|
{
|
|
GuiLock __;
|
|
AppendClipboard(format, String(data, length));
|
|
}
|
|
|
|
void AppendClipboard(const char *format, const String& data)
|
|
{
|
|
GuiLock __;
|
|
LLOG("AppendClipboard " << format);
|
|
Vector<String> s = Split(format, ';');
|
|
for(int i = 0; i < s.GetCount(); i++)
|
|
Ctrl::gclipboard().Put(s[i], ClipData(data));
|
|
}
|
|
|
|
String ReadClipboard(const char *format)
|
|
{
|
|
GuiLock __;
|
|
return Null;
|
|
}
|
|
|
|
const char *ClipFmtsText()
|
|
{
|
|
GuiLock __;
|
|
return "text";
|
|
}
|
|
|
|
void AppendClipboardUnicodeText(const WString& s)
|
|
{
|
|
AppendClipboard(ClipFmtsText(), Value(ToUtf8(s)), NULL);
|
|
}
|
|
|
|
void AppendClipboardText(const String& s)
|
|
{
|
|
AppendClipboard(ClipFmtsText(), Value(ToCharset(CHARSET_UTF8, s)), NULL);
|
|
}
|
|
|
|
String GetString(PasteClip& clip)
|
|
{
|
|
GuiLock __;
|
|
if(clip.IsAvailable("text"))
|
|
return ToCharset(CHARSET_DEFAULT, clip.Get("text"), CHARSET_UTF8);
|
|
return Null;
|
|
}
|
|
|
|
WString GetWString(PasteClip& clip)
|
|
{
|
|
GuiLock __;
|
|
if(clip.IsAvailable("text"))
|
|
return ToUtf32(clip.Get("text"));
|
|
return Null;
|
|
}
|
|
|
|
|
|
bool AcceptText(PasteClip& clip)
|
|
{
|
|
return clip.Accept(ClipFmtsText());
|
|
}
|
|
|
|
static String sText(const Value& data)
|
|
{
|
|
return data;
|
|
}
|
|
|
|
void Append(VectorMap<String, ClipData>& data, const String& text)
|
|
{
|
|
data.GetAdd("text", ClipData(ToCharset(CHARSET_UTF8, text), sText));
|
|
}
|
|
|
|
void Append(VectorMap<String, ClipData>& data, const WString& text)
|
|
{
|
|
data.GetAdd("text", ClipData(ToUtf8(text), sText));
|
|
}
|
|
|
|
String GetTextClip(const WString& text, const String& fmt)
|
|
{
|
|
if(fmt == "text")
|
|
return ToUtf8(text);
|
|
return Null;
|
|
}
|
|
|
|
String GetTextClip(const String& text, const String& fmt)
|
|
{
|
|
if(fmt == "text")
|
|
return ToCharset(CHARSET_UTF8, text);
|
|
return Null;
|
|
}
|
|
|
|
String ReadClipboardText()
|
|
{
|
|
return ToCharset(CHARSET_DEFAULT, Ctrl::gclipboard().Get("text"), CHARSET_UTF8);
|
|
}
|
|
|
|
WString ReadClipboardUnicodeText()
|
|
{
|
|
return ToUtf32(Ctrl::gclipboard().Get("text"));
|
|
}
|
|
|
|
bool IsClipboardAvailable(const char *id)
|
|
{
|
|
return Ctrl::gclipboard().IsAvailable(id);
|
|
}
|
|
|
|
bool IsClipboardAvailableText()
|
|
{
|
|
return Ctrl::gclipboard().IsAvailable("text");
|
|
}
|
|
|
|
const char *ClipFmtsImage()
|
|
{
|
|
return "image";
|
|
}
|
|
|
|
bool AcceptImage(PasteClip& clip)
|
|
{
|
|
GuiLock __;
|
|
return clip.Accept("image");
|
|
}
|
|
|
|
Image GetImage(PasteClip& clip)
|
|
{
|
|
GuiLock __;
|
|
Image m;
|
|
LoadFromString(m, clip.Get("image"));
|
|
return m;
|
|
}
|
|
|
|
Image ReadClipboardImage()
|
|
{
|
|
GuiLock __;
|
|
Image m;
|
|
LoadFromString(m, Ctrl::gclipboard().Get("image"));
|
|
return m;
|
|
}
|
|
|
|
String GetImageClip(const Image& m, const String& fmt)
|
|
{
|
|
Image h = m;
|
|
if(fmt == "image")
|
|
return StoreAsString(h);
|
|
return Null;
|
|
}
|
|
|
|
void AppendClipboardImage(const Image& img)
|
|
{
|
|
GuiLock __;
|
|
if(img.IsEmpty()) return;
|
|
Image h = img;
|
|
AppendClipboard("image", StoreAsString(h));
|
|
}
|
|
|
|
void Append(VectorMap<String, ClipData>& data, const Image& img)
|
|
{
|
|
Image h = img;
|
|
data.Add("image", StoreAsString(h));
|
|
}
|
|
|
|
bool AcceptFiles(PasteClip& clip)
|
|
{
|
|
if(clip.Accept("files")) {
|
|
clip.SetAction(DND_COPY);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsAvailableFiles(PasteClip& clip)
|
|
{
|
|
return clip.IsAvailable("files");
|
|
}
|
|
|
|
Vector<String> GetClipFiles(const String& data)
|
|
{
|
|
Vector<String> r;
|
|
Vector<String> f = Split(data, '\n');
|
|
for(int i = 0; i < f.GetCount(); i++)
|
|
if(f[i].StartsWith("file://"))
|
|
r.Add(UrlDecode(f[i].Mid(7)));
|
|
return r;
|
|
}
|
|
|
|
Vector<String> GetFiles(PasteClip& clip)
|
|
{
|
|
GuiLock __;
|
|
return GetClipFiles(clip.Get("files"));
|
|
}
|
|
|
|
void AppendFiles(VectorMap<String, ClipData>& data, const Vector<String>& files)
|
|
{
|
|
GuiLock __;
|
|
if(files.GetCount() == 0)
|
|
return;
|
|
String h;
|
|
for(int i = 0; i < files.GetCount(); i++)
|
|
h << "file://" << UrlEncode(files[i]) << '\n';
|
|
data.GetAdd("files") = h;
|
|
}
|
|
|
|
Ptr<Ctrl> Ctrl::sel_ctrl;
|
|
|
|
void Ctrl::GuiPlatformSelection(PasteClip& d)
|
|
{
|
|
d.fmt.Clear();
|
|
d.type = 2;
|
|
}
|
|
|
|
String Ctrl::RenderPrimarySelection(const Value& fmt)
|
|
{
|
|
return sel_ctrl ? sel_ctrl->GetSelectionData(fmt) : String();
|
|
}
|
|
|
|
void Ctrl::SetSelectionSource(const char *fmts)
|
|
{
|
|
GuiLock __;
|
|
LLOG("SetSelectionSource " << UPP::Name(this) << ": " << fmts);
|
|
Vector<String> s = Split(fmts, ';');
|
|
sel_ctrl = this;
|
|
for(int i = 0; i < s.GetCount(); i++)
|
|
gselection().Put(s[i], ClipData(s[i], RenderPrimarySelection));
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|