1 // SciTE - Scintilla based Text Editor
2 /** @file GUIGTK.cxx
3 ** Interface to platform GUI facilities.
4 ** Split off from Scintilla's Platform.h to avoid SciTE depending on implementation of Scintilla.
5 **/
6 // Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <time.h>
10
11 #include <string>
12 #include <chrono>
13 #include <sstream>
14
15 #include <gtk/gtk.h>
16
17 #include "Scintilla.h"
18 #include "ScintillaWidget.h"
19
20 #include "GUI.h"
21
22 namespace GUI {
23
StringFromUTF8(const char * s)24 gui_string StringFromUTF8(const char *s) {
25 if (s)
26 return gui_string(s);
27 else
28 return gui_string("");
29 }
30
StringFromUTF8(const std::string & s)31 gui_string StringFromUTF8(const std::string &s) {
32 return s;
33 }
34
UTF8FromString(const gui_string & s)35 std::string UTF8FromString(const gui_string &s) {
36 return s;
37 }
38
StringFromInteger(long i)39 gui_string StringFromInteger(long i) {
40 char number[32];
41 sprintf(number, "%0ld", i);
42 return gui_string(number);
43 }
44
StringFromLongLong(long long i)45 gui_string StringFromLongLong(long long i) {
46 try {
47 std::ostringstream strstrm;
48 strstrm << i;
49 return StringFromUTF8(strstrm.str());
50 } catch (std::exception &) {
51 // Exceptions not enabled on stream but still causes diagnostic in Coverity.
52 // Simply swallow the failure and return the default value.
53 }
54 return gui_string();
55 }
56
LowerCaseUTF8(std::string_view sv)57 std::string LowerCaseUTF8(std::string_view sv) {
58 gchar *lower = g_utf8_strdown(sv.data(), sv.length());
59 const std::string sLower(lower);
60 g_free(lower);
61 return sLower;
62 }
63
PWidget(WindowID wid)64 static GtkWidget *PWidget(WindowID wid) {
65 return static_cast<GtkWidget *>(wid);
66 }
67
Destroy()68 void Window::Destroy() {
69 if (wid)
70 gtk_widget_destroy(GTK_WIDGET(wid));
71 wid = 0;
72 }
73
HasFocus()74 bool Window::HasFocus() {
75 return gtk_widget_has_focus(GTK_WIDGET(wid));
76 }
77
GetPosition()78 Rectangle Window::GetPosition() {
79 // Before any size allocated pretend its 1000 wide so not scrolled
80 Rectangle rc(0, 0, 1000, 1000);
81 if (wid) {
82 GtkAllocation allocation;
83 gtk_widget_get_allocation(PWidget(wid), &allocation);
84 rc.left = allocation.x;
85 rc.top = allocation.y;
86 if (allocation.width > 20) {
87 rc.right = rc.left + allocation.width;
88 rc.bottom = rc.top + allocation.height;
89 }
90 }
91 return rc;
92 }
93
SetPosition(Rectangle rc)94 void Window::SetPosition(Rectangle rc) {
95 GtkAllocation alloc;
96 alloc.x = rc.left;
97 alloc.y = rc.top;
98 alloc.width = rc.Width();
99 alloc.height = rc.Height();
100 gtk_widget_size_allocate(PWidget(wid), &alloc);
101 }
102
GetClientPosition()103 Rectangle Window::GetClientPosition() {
104 // On GTK, the client position is the window position
105 return GetPosition();
106 }
107
Show(bool show)108 void Window::Show(bool show) {
109 if (show)
110 gtk_widget_show(PWidget(wid));
111 }
112
InvalidateAll()113 void Window::InvalidateAll() {
114 if (wid) {
115 gtk_widget_queue_draw(PWidget(wid));
116 }
117 }
118
SetTitle(const char * s)119 void Window::SetTitle(const char *s) {
120 gtk_window_set_title(GTK_WINDOW(wid), s);
121 }
122
CreatePopUp()123 void Menu::CreatePopUp() {
124 Destroy();
125 mid = gtk_menu_new();
126 g_object_ref_sink(G_OBJECT(mid));
127 }
128
Destroy()129 void Menu::Destroy() {
130 if (mid)
131 g_object_unref(mid);
132 mid = 0;
133 }
134
135 #if !GTK_CHECK_VERSION(3,22,0)
MenuPositionFunc(GtkMenu *,gint * x,gint * y,gboolean *,gpointer userData)136 static void MenuPositionFunc(GtkMenu *, gint *x, gint *y, gboolean *, gpointer userData) {
137 sptr_t intFromPointer = GPOINTER_TO_INT(userData);
138 *x = intFromPointer & 0xffff;
139 *y = intFromPointer >> 16;
140 }
141 #endif
142
Show(Point pt G_GNUC_UNUSED,Window &)143 void Menu::Show(Point pt G_GNUC_UNUSED, Window &) {
144 GtkMenu *widget = static_cast<GtkMenu *>(mid);
145 gtk_widget_show_all(GTK_WIDGET(widget));
146 #if GTK_CHECK_VERSION(3,22,0)
147 // Rely on GTK to do the right thing with positioning
148 gtk_menu_popup_at_pointer(widget, NULL);
149 #else
150 int screenHeight = gdk_screen_height();
151 int screenWidth = gdk_screen_width();
152 GtkRequisition requisition;
153 #if GTK_CHECK_VERSION(3,0,0)
154 gtk_widget_get_preferred_size(GTK_WIDGET(widget), NULL, &requisition);
155 #else
156 gtk_widget_size_request(GTK_WIDGET(widget), &requisition);
157 #endif
158 if ((pt.x + requisition.width) > screenWidth) {
159 pt.x = screenWidth - requisition.width;
160 }
161 if ((pt.y + requisition.height) > screenHeight) {
162 pt.y = screenHeight - requisition.height;
163 }
164 gtk_menu_popup(widget, NULL, NULL, MenuPositionFunc,
165 GINT_TO_POINTER((pt.y << 16) | pt.x), 0,
166 gtk_get_current_event_time());
167 #endif
168 }
169
Send(unsigned int msg,uptr_t wParam,sptr_t lParam)170 sptr_t ScintillaPrimitive::Send(unsigned int msg, uptr_t wParam, sptr_t lParam) {
171 return scintilla_send_message(SCINTILLA(GetID()), msg, wParam, lParam);
172 }
173
IsDBCSLeadByte(int codePage,char ch)174 bool IsDBCSLeadByte(int codePage, char ch) {
175 // Byte ranges found in Wikipedia articles with relevant search strings in each case
176 unsigned char uch = static_cast<unsigned char>(ch);
177 switch (codePage) {
178 case 932:
179 // Shift_jis
180 return ((uch >= 0x81) && (uch <= 0x9F)) ||
181 ((uch >= 0xE0) && (uch <= 0xEF));
182 case 936:
183 // GBK
184 return (uch >= 0x81) && (uch <= 0xFE);
185 case 950:
186 // Big5
187 return (uch >= 0x81) && (uch <= 0xFE);
188 // Korean EUC-KR may be code page 949.
189 }
190 return false;
191 }
192
SleepMilliseconds(int sleepTime)193 void SleepMilliseconds(int sleepTime) {
194 g_usleep(sleepTime * 1000);
195 }
196
197 }
198