Bug Summary

File:/rootdir/_build/../src/widget.cc
Warning:line 44, column 1
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name widget.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I src/libbte-2.91.so.0.6500.0.p -I src -I ../src -I . -I .. -I src/bte -I ../src/bte -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/pango-1.0 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/uuid -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/p11-kit-1 -I /usr/include/ctk-3.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -D _FILE_OFFSET_BITS=64 -D G_LOG_DOMAIN="BTE" -D LOCALEDIR="/usr/local/share/locale" -D BTE_DISABLE_DEPRECATION_WARNINGS -D BTE_COMPILATION -U PARSER_INCLUDE_NOP -D CDK_VERSION_MIN_REQUIRED=(G_ENCODE_VERSION(3,18)) -D CDK_VERSION_MAX_ALLOWED=(G_ENCODE_VERSION(3,20)) -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/x86_64-linux-gnu/c++/12 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-address-of-packed-member -Wno-missing-field-initializers -Wno-packed -Wno-switch-enum -Wno-unused-parameter -Wwrite-strings -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/rootdir/_build -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2022-08-07-225954-9680-1 -x c++ ../src/widget.cc
1/*
2 * Copyright © 2008, 2009, 2010, 2018 Christian Persch
3 * Copyright © 2001-2004,2009,2010 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 3 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "config.h"
20
21#include "widget.hh"
22
23#include <sys/wait.h> // for W_EXITCODE
24
25#include <exception>
26#include <new>
27#include <string>
28
29#include "cxx-utils.hh"
30#include "btectk.hh"
31#include "bteptyinternal.hh"
32#include "debug.h"
33
34using namespace std::literals;
35
36namespace bte {
37
38namespace platform {
39
40static void
41im_commit_cb(CtkIMContext* im_context,
42 char const* text,
43 Widget* that) noexcept
44try
This statement is never executed
45{
46 if (text == nullptr)
47 return;
48
49 that->terminal()->im_commit(text);
50}
51catch (...)
52{
53 bte::log_exception();
54}
55
56static void
57im_preedit_start_cb(CtkIMContext* im_context,
58 Widget* that) noexcept
59try
60{
61 _bte_debug_print(BTE_DEBUG_EVENTS, "Input method pre-edit started.\n")do { } while(0);
62 that->terminal()->im_preedit_set_active(true);
63}
64catch (...)
65{
66 bte::log_exception();
67}
68
69static void
70im_preedit_end_cb(CtkIMContext* im_context,
71 Widget* that) noexcept
72try
73{
74 _bte_debug_print(BTE_DEBUG_EVENTS, "Input method pre-edit ended.\n")do { } while(0);
75 that->terminal()->im_preedit_set_active(false);
76}
77catch (...)
78{
79 bte::log_exception();
80}
81
82static void
83im_preedit_changed_cb(CtkIMContext* im_context,
84 Widget* that) noexcept
85try
86{
87 that->im_preedit_changed();
88}
89catch (...)
90{
91 bte::log_exception();
92}
93
94static gboolean
95im_retrieve_surrounding_cb(CtkIMContext* im_context,
96 Widget* that) noexcept
97try
98{
99 _bte_debug_print(BTE_DEBUG_EVENTS, "Input method retrieve-surrounding.\n")do { } while(0);
100 return that->terminal()->im_retrieve_surrounding();
101}
102catch (...)
103{
104 bte::log_exception();
105 return false;
106}
107
108static gboolean
109im_delete_surrounding_cb(CtkIMContext* im_context,
110 int offset,
111 int n_chars,
112 Widget* that) noexcept
113try
114{
115 _bte_debug_print(BTE_DEBUG_EVENTS,do { } while(0)
116 "Input method delete-surrounding offset %d n-chars %d.\n",do { } while(0)
117 offset, n_chars)do { } while(0);
118 return that->terminal()->im_delete_surrounding(offset, n_chars);
119}
120catch (...)
121{
122 bte::log_exception();
123 return false;
124}
125
126static void
127settings_notify_cb(CtkSettings* settings,
128 GParamSpec* pspec,
129 bte::platform::Widget* that) noexcept
130try
131{
132 that->settings_changed();
133}
134catch (...)
135{
136 bte::log_exception();
137}
138
139Widget::Widget(BteTerminal* t)
140 : m_widget{&t->widget},
141 m_hscroll_policy{CTK_SCROLL_NATURAL},
142 m_vscroll_policy{CTK_SCROLL_NATURAL}
143{
144 ctk_widget_set_can_focus(ctk(), true);
145
146 /* We do our own redrawing. */
147 // FIXMEchpe is this still necessary?
148 ctk_widget_set_redraw_on_allocate(ctk(), false);
149
150 /* Until Terminal init is completely fixed, use zero'd memory */
151 auto place = g_malloc0(sizeof(bte::terminal::Terminal));
152 m_terminal = new (place) bte::terminal::Terminal(this, t);
153}
154
155Widget::~Widget() noexcept
156try
157{
158 g_signal_handlers_disconnect_matched(ctk_widget_get_settings(m_widget),
159 G_SIGNAL_MATCH_DATA,
160 0, 0, NULL__null, NULL__null,
161 this);
162
163 m_widget = nullptr;
164
165 m_terminal->~Terminal();
166 g_free(m_terminal);
167}
168catch (...)
169{
170 bte::log_exception();
171}
172
173void
174Widget::beep() noexcept
175{
176 if (realized())
177 cdk_window_beep(ctk_widget_get_window(m_widget));
178}
179
180bte::glib::RefPtr<CdkCursor>
181Widget::create_cursor(CdkCursorType cursor_type) const noexcept
182{
183 return bte::glib::take_ref(cdk_cursor_new_for_display(ctk_widget_get_display(m_widget), cursor_type));
184}
185
186void
187Widget::set_cursor(CdkCursor* cursor) noexcept
188{
189 cdk_window_set_cursor(m_event_window, cursor);
190}
191
192void
193Widget::set_cursor(Cursor const& cursor) noexcept
194{
195 if (!realized())
196 return;
197
198 auto display = ctk_widget_get_display(m_widget);
199 CdkCursor* cdk_cursor{nullptr};
200 switch (cursor.index()) {
201 case 0:
202 cdk_cursor = cdk_cursor_new_from_name(display, std::get<0>(cursor).c_str());
203 break;
204 case 1:
205 cdk_cursor = std::get<1>(cursor).get();
206 if (cdk_cursor != nullptr &&
207 cdk_cursor_get_display(cdk_cursor) == display) {
208 g_object_ref(cdk_cursor);
209 } else {
210 cdk_cursor = nullptr;
211 }
212 break;
213 case 2:
214 cdk_cursor = cdk_cursor_new_for_display(display, std::get<2>(cursor));
215 break;
216 }
217
218 set_cursor(cdk_cursor);
219 if (cdk_cursor)
220 g_object_unref(cdk_cursor);
221}
222
223void
224Widget::constructed() noexcept
225{
226 /* Set the style as early as possible, before CTK+ starts
227 * invoking various callbacks. This is needed in order to
228 * compute the initial geometry correctly in presence of
229 * non-default padding, see bug 787710.
230 */
231 style_updated();
232}
233
234void
235Widget::dispose() noexcept
236{
237 if (m_terminal->terminate_child()) {
238 int status = W_EXITCODE(0, SIGKILL)((0) << 8 | (9));
239 emit_child_exited(status);
240 }
241}
242
243void
244Widget::emit_child_exited(int status) noexcept
245{
246 _bte_debug_print(BTE_DEBUG_SIGNALS, "Emitting `child-exited'.\n")do { } while(0);
247 g_signal_emit(object(), signals[SIGNAL_CHILD_EXITED], 0, status);
248}
249
250void
251Widget::emit_eof() noexcept
252{
253 _bte_debug_print(BTE_DEBUG_SIGNALS, "Emitting `eof'.\n")do { } while(0);
254 g_signal_emit(object(), signals[SIGNAL_EOF], 0);
255}
256
257bool
258Widget::im_filter_keypress(bte::terminal::KeyEvent const& event) noexcept
259{
260 // FIXMEchpe this can only be called when realized, so the m_im_context check is redundant
261 return m_im_context &&
262 ctk_im_context_filter_keypress(m_im_context.get(),
263 reinterpret_cast<CdkEventKey*>(event.platform_event()));
264}
265
266void
267Widget::im_focus_in() noexcept
268{
269 ctk_im_context_focus_in(m_im_context.get());
270}
271
272void
273Widget::im_focus_out() noexcept
274{
275 ctk_im_context_focus_out(m_im_context.get());
276}
277
278void
279Widget::im_preedit_changed() noexcept
280{
281 char* str = nullptr;
282 PangoAttrList* attrs = nullptr;
283 int cursorpos = 0;
284
285 ctk_im_context_get_preedit_string(m_im_context.get(), &str, &attrs, &cursorpos);
286 _bte_debug_print(BTE_DEBUG_EVENTS, "Input method pre-edit changed (%s,%d).\n",do { } while(0)
287 str, cursorpos)do { } while(0);
288
289 if (str != nullptr)
290 m_terminal->im_preedit_changed(str, cursorpos, {attrs, &pango_attr_list_unref});
291 else
292 pango_attr_list_unref(attrs);
293
294 g_free(str);
295}
296
297void
298Widget::im_set_cursor_location(cairo_rectangle_int_t const* rect) noexcept
299{
300 ctk_im_context_set_cursor_location(m_im_context.get(), rect);
301}
302
303unsigned
304Widget::read_modifiers_from_cdk(CdkEvent* event) const noexcept
305{
306 /* Read the modifiers. See bug #663779 for more information on why we do this. */
307 auto mods = CdkModifierType{};
308 if (!cdk_event_get_state(event, &mods))
309 return 0;
310
311 #if 1
312 /* HACK! Treat META as ALT; see bug #663779. */
313 if (mods & CDK_META_MASK)
314 mods = CdkModifierType(mods | CDK_MOD1_MASK);
315 #endif
316
317 /* Map non-virtual modifiers to virtual modifiers (Super, Hyper, Meta) */
318 auto display = cdk_window_get_display(cdk_event_get_window(event));
319 auto keymap = cdk_keymap_get_for_display(display);
320 cdk_keymap_add_virtual_modifiers(keymap, &mods);
321
322 return unsigned(mods);
323}
324
325unsigned
326Widget::key_event_translate_ctrlkey(bte::terminal::KeyEvent const& event) const noexcept
327{
328 if (event.keyval() < 128)
329 return event.keyval();
330
331 auto display = cdk_window_get_display(cdk_event_get_window(event.platform_event()));
332 auto keymap = cdk_keymap_get_for_display(display);
333 auto keyval = unsigned{event.keyval()};
334
335 /* Try groups in order to find one mapping the key to ASCII */
336 for (auto i = unsigned{0}; i < 4; i++) {
337 auto consumed_modifiers = CdkModifierType{};
338 cdk_keymap_translate_keyboard_state (keymap,
339 event.keycode(),
340 CdkModifierType(event.modifiers()),
341 i,
342 &keyval, NULL__null, NULL__null, &consumed_modifiers);
343 if (keyval < 128) {
344 _bte_debug_print (BTE_DEBUG_EVENTS,do { } while(0)
345 "ctrl+Key, group=%d de-grouped into keyval=0x%x\n",do { } while(0)
346 event.group(), keyval)do { } while(0);
347 break;
348 }
349 }
350
351 return keyval;
352}
353
354bte::terminal::KeyEvent
355Widget::key_event_from_cdk(CdkEventKey* event) const
356{
357 auto type = bte::terminal::EventBase::Type{};
358 switch (cdk_event_get_event_type(reinterpret_cast<CdkEvent*>(event))) {
359 case CDK_KEY_PRESS: type = bte::terminal::KeyEvent::Type::eKEY_PRESS; break;
360 case CDK_KEY_RELEASE: type = bte::terminal::KeyEvent::Type::eKEY_RELEASE; break;
361 default: g_assert_not_reached()do { g_assertion_message_expr ("BTE", "../src/widget.cc", 361
, ((const char*) (__PRETTY_FUNCTION__)), __null); } while (0)
; return {};
362 }
363
364 auto base_event = reinterpret_cast<CdkEvent*>(event);
365 return {base_event,
366 type,
367 event->time,
368 read_modifiers_from_cdk(base_event),
369 event->keyval,
370 event->hardware_keycode, // cdk_event_get_scancode(event),
371 event->group,
372 event->is_modifier != 0};
373}
374
375std::optional<bte::terminal::MouseEvent>
376Widget::mouse_event_from_cdk(CdkEvent* event) const
377{
378 auto type = bte::terminal::EventBase::Type{};
379 switch (cdk_event_get_event_type(event)) {
380 case CDK_2BUTTON_PRESS: type = bte::terminal::MouseEvent::Type::eMOUSE_DOUBLE_PRESS; break;
381 case CDK_3BUTTON_PRESS: type = bte::terminal::MouseEvent::Type::eMOUSE_TRIPLE_PRESS; break;
382 case CDK_BUTTON_PRESS: type = bte::terminal::MouseEvent::Type::eMOUSE_PRESS; break;
383 case CDK_BUTTON_RELEASE: type = bte::terminal::MouseEvent::Type::eMOUSE_RELEASE; break;
384 case CDK_ENTER_NOTIFY: type = bte::terminal::MouseEvent::Type::eMOUSE_ENTER; break;
385 case CDK_LEAVE_NOTIFY: type = bte::terminal::MouseEvent::Type::eMOUSE_LEAVE; break;
386 case CDK_MOTION_NOTIFY: type = bte::terminal::MouseEvent::Type::eMOUSE_MOTION; break;
387 case CDK_SCROLL: type = bte::terminal::MouseEvent::Type::eMOUSE_SCROLL; break;
388 default:
389 return std::nullopt;
390 }
391
392 auto x = double{};
393 auto y = double{};
394 if (cdk_event_get_window(event) != m_event_window ||
395 !cdk_event_get_coords(event, &x, &y))
396 x = y = -1.; // FIXMEchpe or return std::nullopt?
397
398 auto button = unsigned{0};
399 (void)cdk_event_get_button(event, &button);
400
401 auto mouse_event = bte::terminal::MouseEvent{event,
402 type,
403 cdk_event_get_time(event),
404 read_modifiers_from_cdk(event),
405 bte::terminal::MouseEvent::Button(button),
406 x,
407 y};
408 return mouse_event;
409}
410
411void
412Widget::map() noexcept
413{
414 if (m_event_window)
415 cdk_window_show_unraised(m_event_window);
416}
417
418bool
419Widget::primary_paste_enabled() const noexcept
420{
421 auto primary_paste = gboolean{};
422 g_object_get(ctk_widget_get_settings(ctk()),
423 "ctk-enable-primary-paste", &primary_paste,
424 nullptr);
425
426 return primary_paste != false;
427}
428
429void
430Widget::realize() noexcept
431{
432 // m_mouse_cursor_over_widget = false; /* We'll receive an enter_notify_event if the window appears under the cursor. */
433
434 /* Create stock cursors */
435 m_default_cursor = create_cursor(BTE_DEFAULT_CURSORCDK_XTERM);
436 m_invisible_cursor = create_cursor(CDK_BLANK_CURSOR);
437 m_mousing_cursor = create_cursor(BTE_MOUSING_CURSORCDK_LEFT_PTR);
438 if (_bte_debug_on(BTE_DEBUG_HYPERLINK))
439 /* Differ from the standard regex match cursor in debug mode. */
440 m_hyperlink_cursor = create_cursor(BTE_HYPERLINK_CURSOR_DEBUGCDK_SPIDER);
441 else
442 m_hyperlink_cursor = create_cursor(BTE_HYPERLINK_CURSORCDK_HAND2);
443
444 /* Create an input window for the widget. */
445 auto allocation = m_terminal->get_allocated_rect();
446 CdkWindowAttr attributes;
447 attributes.window_type = CDK_WINDOW_CHILD;
448 attributes.x = allocation.x;
449 attributes.y = allocation.y;
450 attributes.width = allocation.width;
451 attributes.height = allocation.height;
452 attributes.wclass = CDK_INPUT_ONLY;
453 attributes.visual = ctk_widget_get_visual(m_widget);
454 attributes.event_mask =
455 ctk_widget_get_events(m_widget) |
456 CDK_EXPOSURE_MASK |
457 CDK_FOCUS_CHANGE_MASK |
458 CDK_SMOOTH_SCROLL_MASK |
459 CDK_SCROLL_MASK |
460 CDK_BUTTON_PRESS_MASK |
461 CDK_BUTTON_RELEASE_MASK |
462 CDK_POINTER_MOTION_MASK |
463 CDK_BUTTON1_MOTION_MASK |
464 CDK_ENTER_NOTIFY_MASK |
465 CDK_LEAVE_NOTIFY_MASK |
466 CDK_KEY_PRESS_MASK |
467 CDK_KEY_RELEASE_MASK;
468 attributes.cursor = m_default_cursor.get();
469 guint attributes_mask =
470 CDK_WA_X |
471 CDK_WA_Y |
472 (attributes.visual ? CDK_WA_VISUAL : 0) |
473 CDK_WA_CURSOR;
474
475 m_event_window = cdk_window_new(ctk_widget_get_parent_window (m_widget),
476 &attributes, attributes_mask);
477 ctk_widget_register_window(m_widget, m_event_window);
478
479 assert(!m_im_context)(static_cast <bool> (!m_im_context) ? void (0) : __assert_fail
("!m_im_context", "../src/widget.cc", 479, __extension__ __PRETTY_FUNCTION__
))
;
480 m_im_context.reset(ctk_im_multicontext_new());
481#if CTK_CHECK_VERSION (3, 24, 14)((3) > (3) || ((3) == (3) && (25) > (24)) || ((
3) == (3) && (25) == (24) && (2) >= (14)))
482 g_object_set(m_im_context.get(),
483 "input-purpose", CTK_INPUT_PURPOSE_TERMINAL,
484 nullptr);
485#endif
486 ctk_im_context_set_client_window(m_im_context.get(), m_event_window);
487 g_signal_connect(m_im_context.get(), "commit",g_signal_connect_data ((m_im_context.get()), ("commit"), (((GCallback
) (im_commit_cb))), (this), __null, (GConnectFlags) 0)
488 G_CALLBACK(im_commit_cb), this)g_signal_connect_data ((m_im_context.get()), ("commit"), (((GCallback
) (im_commit_cb))), (this), __null, (GConnectFlags) 0)
;
489 g_signal_connect(m_im_context.get(), "preedit-start",g_signal_connect_data ((m_im_context.get()), ("preedit-start"
), (((GCallback) (im_preedit_start_cb))), (this), __null, (GConnectFlags
) 0)
490 G_CALLBACK(im_preedit_start_cb), this)g_signal_connect_data ((m_im_context.get()), ("preedit-start"
), (((GCallback) (im_preedit_start_cb))), (this), __null, (GConnectFlags
) 0)
;
491 g_signal_connect(m_im_context.get(), "preedit-changed",g_signal_connect_data ((m_im_context.get()), ("preedit-changed"
), (((GCallback) (im_preedit_changed_cb))), (this), __null, (
GConnectFlags) 0)
492 G_CALLBACK(im_preedit_changed_cb), this)g_signal_connect_data ((m_im_context.get()), ("preedit-changed"
), (((GCallback) (im_preedit_changed_cb))), (this), __null, (
GConnectFlags) 0)
;
493 g_signal_connect(m_im_context.get(), "preedit-end",g_signal_connect_data ((m_im_context.get()), ("preedit-end"),
(((GCallback) (im_preedit_end_cb))), (this), __null, (GConnectFlags
) 0)
494 G_CALLBACK(im_preedit_end_cb), this)g_signal_connect_data ((m_im_context.get()), ("preedit-end"),
(((GCallback) (im_preedit_end_cb))), (this), __null, (GConnectFlags
) 0)
;
495 g_signal_connect(m_im_context.get(), "retrieve-surrounding",g_signal_connect_data ((m_im_context.get()), ("retrieve-surrounding"
), (((GCallback) (im_retrieve_surrounding_cb))), (this), __null
, (GConnectFlags) 0)
496 G_CALLBACK(im_retrieve_surrounding_cb), this)g_signal_connect_data ((m_im_context.get()), ("retrieve-surrounding"
), (((GCallback) (im_retrieve_surrounding_cb))), (this), __null
, (GConnectFlags) 0)
;
497 g_signal_connect(m_im_context.get(), "delete-surrounding",g_signal_connect_data ((m_im_context.get()), ("delete-surrounding"
), (((GCallback) (im_delete_surrounding_cb))), (this), __null
, (GConnectFlags) 0)
498 G_CALLBACK(im_delete_surrounding_cb), this)g_signal_connect_data ((m_im_context.get()), ("delete-surrounding"
), (((GCallback) (im_delete_surrounding_cb))), (this), __null
, (GConnectFlags) 0)
;
499 ctk_im_context_set_use_preedit(m_im_context.get(), true);
500
501 m_terminal->widget_realize();
502}
503
504void
505Widget::screen_changed(CdkScreen *previous_screen) noexcept
506{
507 auto cdk_screen = ctk_widget_get_screen(m_widget);
508 if (previous_screen != nullptr &&
509 (cdk_screen != previous_screen || cdk_screen == nullptr)) {
510 auto settings = ctk_settings_get_for_screen(previous_screen);
511 g_signal_handlers_disconnect_matched(settings, G_SIGNAL_MATCH_DATA,
512 0, 0, nullptr, nullptr,
513 this);
514 }
515
516 if (cdk_screen == previous_screen || cdk_screen == nullptr)
517 return;
518
519 settings_changed();
520
521 auto settings = ctk_widget_get_settings(m_widget);
522 g_signal_connect (settings, "notify::ctk-cursor-blink",g_signal_connect_data ((settings), ("notify::ctk-cursor-blink"
), (((GCallback) (settings_notify_cb))), (this), __null, (GConnectFlags
) 0)
523 G_CALLBACK(settings_notify_cb), this)g_signal_connect_data ((settings), ("notify::ctk-cursor-blink"
), (((GCallback) (settings_notify_cb))), (this), __null, (GConnectFlags
) 0)
;
524 g_signal_connect (settings, "notify::ctk-cursor-blink-time",g_signal_connect_data ((settings), ("notify::ctk-cursor-blink-time"
), (((GCallback) (settings_notify_cb))), (this), __null, (GConnectFlags
) 0)
525 G_CALLBACK(settings_notify_cb), this)g_signal_connect_data ((settings), ("notify::ctk-cursor-blink-time"
), (((GCallback) (settings_notify_cb))), (this), __null, (GConnectFlags
) 0)
;
526 g_signal_connect (settings, "notify::ctk-cursor-blink-timeout",g_signal_connect_data ((settings), ("notify::ctk-cursor-blink-timeout"
), (((GCallback) (settings_notify_cb))), (this), __null, (GConnectFlags
) 0)
527 G_CALLBACK(settings_notify_cb), this)g_signal_connect_data ((settings), ("notify::ctk-cursor-blink-timeout"
), (((GCallback) (settings_notify_cb))), (this), __null, (GConnectFlags
) 0)
;
528}
529
530void
531Widget::settings_changed() noexcept
532{
533 auto blink = gboolean{};
534 auto blink_time = int{};
535 auto blink_timeout = int{};
536 g_object_get(ctk_widget_get_settings(m_widget),
537 "ctk-cursor-blink", &blink,
538 "ctk-cursor-blink-time", &blink_time,
539 "ctk-cursor-blink-timeout", &blink_timeout,
540 nullptr);
541
542 _bte_debug_print(BTE_DEBUG_MISC,do { } while(0)
543 "Cursor blinking settings: blink=%d time=%d timeout=%d\n",do { } while(0)
544 blink, blink_time, blink_timeout)do { } while(0);
545
546 m_terminal->set_blink_settings(blink, blink_time, blink_timeout);
547}
548
549void
550Widget::set_cursor(CursorType type) noexcept
551{
552 switch (type) {
553 case CursorType::eDefault: return set_cursor(m_default_cursor.get());
554 case CursorType::eInvisible: return set_cursor(m_invisible_cursor.get());
555 case CursorType::eMousing: return set_cursor(m_mousing_cursor.get());
556 case CursorType::eHyperlink: return set_cursor(m_hyperlink_cursor.get());
557 }
558}
559
560bool
561Widget::set_pty(BtePty* pty_obj) noexcept
562{
563 if (pty() == pty_obj)
564 return false;
565
566 m_pty = bte::glib::make_ref(pty_obj);
567 terminal()->set_pty(_bte_pty_get_impl(pty()));
568
569 return true;
570}
571
572bool
573Widget::set_word_char_exceptions(std::optional<std::string_view> stropt)
574{
575 if (m_word_char_exceptions == stropt)
576 return false;
577
578 if (terminal()->set_word_char_exceptions(stropt)) {
579 m_word_char_exceptions = stropt;
580 return true;
581 }
582
583 return false;
584}
585
586void
587Widget::unset_pty() noexcept
588{
589 if (!pty())
590 return;
591
592 /* This is only called from Terminal, so we need
593 * to explicitly notify the BteTerminal:pty property,
594 * but we do NOT need to call Terminal::set_pty(nullptr).
595 */
596 m_pty.reset();
597 g_object_notify_by_pspec(object(), pspecs[PROP_PTY]);
598}
599
600void
601Widget::size_allocate(CtkAllocation* allocation) noexcept
602{
603 m_terminal->widget_size_allocate(allocation);
604
605 if (realized())
606 cdk_window_move_resize(m_event_window,
607 allocation->x,
608 allocation->y,
609 allocation->width,
610 allocation->height);
611}
612
613bool
614Widget::should_emit_signal(int id) noexcept
615{
616 return g_signal_has_handler_pending(object(),
617 signals[id],
618 0 /* detail */,
619 false /* not interested in blocked handlers */) != FALSE(0);
620}
621
622void
623Widget::style_updated() noexcept
624{
625 auto padding = CtkBorder{};
626 auto context = ctk_widget_get_style_context(ctk());
627 ctk_style_context_get_padding(context, ctk_style_context_get_state(context),
628 &padding);
629 m_terminal->set_border_padding(&padding);
630
631 auto aspect = float{};
632 ctk_widget_style_get(ctk(), "cursor-aspect-ratio", &aspect, nullptr);
633 m_terminal->set_cursor_aspect(aspect);
634
635 m_terminal->widget_style_updated();
636}
637
638void
639Widget::unmap() noexcept
640{
641 m_terminal->widget_unmap();
642
643 if (m_event_window)
644 cdk_window_hide(m_event_window);
645}
646
647void
648Widget::unrealize() noexcept
649{
650 m_terminal->widget_unrealize();
651
652 m_default_cursor.reset();
653 m_invisible_cursor.reset();
654 m_mousing_cursor.reset();
655 m_hyperlink_cursor.reset();
656
657 /* Shut down input methods. */
658 assert(m_im_context)(static_cast <bool> (m_im_context) ? void (0) : __assert_fail
("m_im_context", "../src/widget.cc", 658, __extension__ __PRETTY_FUNCTION__
))
;
659 g_signal_handlers_disconnect_matched(m_im_context.get(),
660 G_SIGNAL_MATCH_DATA,
661 0, 0, NULL__null, NULL__null,
662 this);
663 m_terminal->im_preedit_reset();
664 ctk_im_context_set_client_window(m_im_context.get(), nullptr);
665 m_im_context.reset();
666
667 /* Destroy input window */
668 ctk_widget_unregister_window(m_widget, m_event_window);
669 cdk_window_destroy(m_event_window);
670 m_event_window = nullptr;
671}
672
673} // namespace platform
674
675} // namespace bte