17d62b00eSchristos /* TUI windows implemented in Python 27d62b00eSchristos 3*6881a400Schristos Copyright (C) 2020-2023 Free Software Foundation, Inc. 47d62b00eSchristos 57d62b00eSchristos This file is part of GDB. 67d62b00eSchristos 77d62b00eSchristos This program is free software; you can redistribute it and/or modify 87d62b00eSchristos it under the terms of the GNU General Public License as published by 97d62b00eSchristos the Free Software Foundation; either version 3 of the License, or 107d62b00eSchristos (at your option) any later version. 117d62b00eSchristos 127d62b00eSchristos This program is distributed in the hope that it will be useful, 137d62b00eSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 147d62b00eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 157d62b00eSchristos GNU General Public License for more details. 167d62b00eSchristos 177d62b00eSchristos You should have received a copy of the GNU General Public License 187d62b00eSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 197d62b00eSchristos 207d62b00eSchristos 217d62b00eSchristos #include "defs.h" 227d62b00eSchristos #include "arch-utils.h" 237d62b00eSchristos #include "python-internal.h" 247d62b00eSchristos 257d62b00eSchristos #ifdef TUI 267d62b00eSchristos 277d62b00eSchristos /* Note that Python's public headers may define HAVE_NCURSES_H, so if 287d62b00eSchristos we unconditionally include this (outside the #ifdef above), then we 297d62b00eSchristos can get a compile error when ncurses is not in fact installed. See 307d62b00eSchristos PR tui/25597; or the upstream Python bug 317d62b00eSchristos https://bugs.python.org/issue20768. */ 327d62b00eSchristos #include "gdb_curses.h" 337d62b00eSchristos 347d62b00eSchristos #include "tui/tui-data.h" 357d62b00eSchristos #include "tui/tui-io.h" 367d62b00eSchristos #include "tui/tui-layout.h" 377d62b00eSchristos #include "tui/tui-wingeneral.h" 387d62b00eSchristos #include "tui/tui-winsource.h" 397d62b00eSchristos 407d62b00eSchristos class tui_py_window; 417d62b00eSchristos 427d62b00eSchristos /* A PyObject representing a TUI window. */ 437d62b00eSchristos 447d62b00eSchristos struct gdbpy_tui_window 457d62b00eSchristos { 467d62b00eSchristos PyObject_HEAD 477d62b00eSchristos 487d62b00eSchristos /* The TUI window, or nullptr if the window has been deleted. */ 497d62b00eSchristos tui_py_window *window; 50*6881a400Schristos 51*6881a400Schristos /* Return true if this object is valid. */ 52*6881a400Schristos bool is_valid () const; 537d62b00eSchristos }; 547d62b00eSchristos 557d62b00eSchristos extern PyTypeObject gdbpy_tui_window_object_type 567d62b00eSchristos CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("gdbpy_tui_window"); 577d62b00eSchristos 587d62b00eSchristos /* A TUI window written in Python. */ 597d62b00eSchristos 607d62b00eSchristos class tui_py_window : public tui_win_info 617d62b00eSchristos { 627d62b00eSchristos public: 637d62b00eSchristos 647d62b00eSchristos tui_py_window (const char *name, gdbpy_ref<gdbpy_tui_window> wrapper) 657d62b00eSchristos : m_name (name), 667d62b00eSchristos m_wrapper (std::move (wrapper)) 677d62b00eSchristos { 687d62b00eSchristos m_wrapper->window = this; 697d62b00eSchristos } 707d62b00eSchristos 717d62b00eSchristos ~tui_py_window (); 727d62b00eSchristos 737d62b00eSchristos DISABLE_COPY_AND_ASSIGN (tui_py_window); 747d62b00eSchristos 757d62b00eSchristos /* Set the "user window" to the indicated reference. The user 767d62b00eSchristos window is the object returned the by user-defined window 777d62b00eSchristos constructor. */ 787d62b00eSchristos void set_user_window (gdbpy_ref<> &&user_window) 797d62b00eSchristos { 807d62b00eSchristos m_window = std::move (user_window); 817d62b00eSchristos } 827d62b00eSchristos 837d62b00eSchristos const char *name () const override 847d62b00eSchristos { 857d62b00eSchristos return m_name.c_str (); 867d62b00eSchristos } 877d62b00eSchristos 887d62b00eSchristos void rerender () override; 897d62b00eSchristos void do_scroll_vertical (int num_to_scroll) override; 907d62b00eSchristos void do_scroll_horizontal (int num_to_scroll) override; 917d62b00eSchristos 92*6881a400Schristos void refresh_window () override 93*6881a400Schristos { 94*6881a400Schristos if (m_inner_window != nullptr) 95*6881a400Schristos { 96*6881a400Schristos wnoutrefresh (handle.get ()); 97*6881a400Schristos touchwin (m_inner_window.get ()); 98*6881a400Schristos tui_wrefresh (m_inner_window.get ()); 99*6881a400Schristos } 100*6881a400Schristos else 101*6881a400Schristos tui_win_info::refresh_window (); 102*6881a400Schristos } 103*6881a400Schristos 104*6881a400Schristos void click (int mouse_x, int mouse_y, int mouse_button) override; 105*6881a400Schristos 1067d62b00eSchristos /* Erase and re-box the window. */ 1077d62b00eSchristos void erase () 1087d62b00eSchristos { 109*6881a400Schristos if (is_visible () && m_inner_window != nullptr) 1107d62b00eSchristos { 111*6881a400Schristos werase (m_inner_window.get ()); 1127d62b00eSchristos check_and_display_highlight_if_needed (); 1137d62b00eSchristos } 1147d62b00eSchristos } 1157d62b00eSchristos 116*6881a400Schristos /* Write STR to the window. FULL_WINDOW is true to erase the window 117*6881a400Schristos contents beforehand. */ 118*6881a400Schristos void output (const char *str, bool full_window); 1197d62b00eSchristos 1207d62b00eSchristos /* A helper function to compute the viewport width. */ 1217d62b00eSchristos int viewport_width () const 1227d62b00eSchristos { 1237d62b00eSchristos return std::max (0, width - 2); 1247d62b00eSchristos } 1257d62b00eSchristos 1267d62b00eSchristos /* A helper function to compute the viewport height. */ 1277d62b00eSchristos int viewport_height () const 1287d62b00eSchristos { 1297d62b00eSchristos return std::max (0, height - 2); 1307d62b00eSchristos } 1317d62b00eSchristos 1327d62b00eSchristos private: 1337d62b00eSchristos 1347d62b00eSchristos /* The name of this window. */ 1357d62b00eSchristos std::string m_name; 1367d62b00eSchristos 137*6881a400Schristos /* We make our own inner window, so that it is easy to print without 138*6881a400Schristos overwriting the border. */ 139*6881a400Schristos std::unique_ptr<WINDOW, curses_deleter> m_inner_window; 140*6881a400Schristos 1417d62b00eSchristos /* The underlying Python window object. */ 1427d62b00eSchristos gdbpy_ref<> m_window; 1437d62b00eSchristos 1447d62b00eSchristos /* The Python wrapper for this object. */ 1457d62b00eSchristos gdbpy_ref<gdbpy_tui_window> m_wrapper; 1467d62b00eSchristos }; 1477d62b00eSchristos 148*6881a400Schristos /* See gdbpy_tui_window declaration above. */ 149*6881a400Schristos 150*6881a400Schristos bool 151*6881a400Schristos gdbpy_tui_window::is_valid () const 152*6881a400Schristos { 153*6881a400Schristos return window != nullptr && tui_active; 154*6881a400Schristos } 155*6881a400Schristos 1567d62b00eSchristos tui_py_window::~tui_py_window () 1577d62b00eSchristos { 158*6881a400Schristos gdbpy_enter enter_py; 1597d62b00eSchristos 1607d62b00eSchristos /* This can be null if the user-provided Python construction 1617d62b00eSchristos function failed. */ 1627d62b00eSchristos if (m_window != nullptr 1637d62b00eSchristos && PyObject_HasAttrString (m_window.get (), "close")) 1647d62b00eSchristos { 1657d62b00eSchristos gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "close", 1667d62b00eSchristos nullptr)); 1677d62b00eSchristos if (result == nullptr) 1687d62b00eSchristos gdbpy_print_stack (); 1697d62b00eSchristos } 1707d62b00eSchristos 1717d62b00eSchristos /* Unlink. */ 1727d62b00eSchristos m_wrapper->window = nullptr; 1737d62b00eSchristos /* Explicitly free the Python references. We have to do this 1747d62b00eSchristos manually because we need to hold the GIL while doing so. */ 1757d62b00eSchristos m_wrapper.reset (nullptr); 1767d62b00eSchristos m_window.reset (nullptr); 1777d62b00eSchristos } 1787d62b00eSchristos 1797d62b00eSchristos void 1807d62b00eSchristos tui_py_window::rerender () 1817d62b00eSchristos { 182*6881a400Schristos tui_win_info::rerender (); 183*6881a400Schristos 184*6881a400Schristos gdbpy_enter enter_py; 185*6881a400Schristos 186*6881a400Schristos int h = viewport_height (); 187*6881a400Schristos int w = viewport_width (); 188*6881a400Schristos if (h == 0 || w == 0) 189*6881a400Schristos { 190*6881a400Schristos /* The window would be too small, so just remove the 191*6881a400Schristos contents. */ 192*6881a400Schristos m_inner_window.reset (nullptr); 193*6881a400Schristos return; 194*6881a400Schristos } 195*6881a400Schristos m_inner_window.reset (newwin (h, w, y + 1, x + 1)); 1967d62b00eSchristos 1977d62b00eSchristos if (PyObject_HasAttrString (m_window.get (), "render")) 1987d62b00eSchristos { 1997d62b00eSchristos gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "render", 2007d62b00eSchristos nullptr)); 2017d62b00eSchristos if (result == nullptr) 2027d62b00eSchristos gdbpy_print_stack (); 2037d62b00eSchristos } 2047d62b00eSchristos } 2057d62b00eSchristos 2067d62b00eSchristos void 2077d62b00eSchristos tui_py_window::do_scroll_horizontal (int num_to_scroll) 2087d62b00eSchristos { 209*6881a400Schristos gdbpy_enter enter_py; 2107d62b00eSchristos 2117d62b00eSchristos if (PyObject_HasAttrString (m_window.get (), "hscroll")) 2127d62b00eSchristos { 2137d62b00eSchristos gdbpy_ref<> result (PyObject_CallMethod (m_window.get(), "hscroll", 2147d62b00eSchristos "i", num_to_scroll, nullptr)); 2157d62b00eSchristos if (result == nullptr) 2167d62b00eSchristos gdbpy_print_stack (); 2177d62b00eSchristos } 2187d62b00eSchristos } 2197d62b00eSchristos 2207d62b00eSchristos void 2217d62b00eSchristos tui_py_window::do_scroll_vertical (int num_to_scroll) 2227d62b00eSchristos { 223*6881a400Schristos gdbpy_enter enter_py; 2247d62b00eSchristos 2257d62b00eSchristos if (PyObject_HasAttrString (m_window.get (), "vscroll")) 2267d62b00eSchristos { 2277d62b00eSchristos gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "vscroll", 2287d62b00eSchristos "i", num_to_scroll, nullptr)); 2297d62b00eSchristos if (result == nullptr) 2307d62b00eSchristos gdbpy_print_stack (); 2317d62b00eSchristos } 2327d62b00eSchristos } 2337d62b00eSchristos 2347d62b00eSchristos void 235*6881a400Schristos tui_py_window::click (int mouse_x, int mouse_y, int mouse_button) 2367d62b00eSchristos { 237*6881a400Schristos gdbpy_enter enter_py; 2387d62b00eSchristos 239*6881a400Schristos if (PyObject_HasAttrString (m_window.get (), "click")) 2407d62b00eSchristos { 241*6881a400Schristos gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "click", 242*6881a400Schristos "iii", mouse_x, mouse_y, 243*6881a400Schristos mouse_button)); 244*6881a400Schristos if (result == nullptr) 245*6881a400Schristos gdbpy_print_stack (); 2467d62b00eSchristos } 247*6881a400Schristos } 248*6881a400Schristos 249*6881a400Schristos void 250*6881a400Schristos tui_py_window::output (const char *text, bool full_window) 251*6881a400Schristos { 252*6881a400Schristos if (m_inner_window != nullptr) 253*6881a400Schristos { 254*6881a400Schristos if (full_window) 255*6881a400Schristos werase (m_inner_window.get ()); 256*6881a400Schristos 257*6881a400Schristos tui_puts (text, m_inner_window.get ()); 258*6881a400Schristos if (full_window) 259*6881a400Schristos check_and_display_highlight_if_needed (); 2607d62b00eSchristos else 261*6881a400Schristos tui_wrefresh (m_inner_window.get ()); 2627d62b00eSchristos } 2637d62b00eSchristos } 2647d62b00eSchristos 2657d62b00eSchristos 2667d62b00eSchristos 2677d62b00eSchristos /* A callable that is used to create a TUI window. It wraps the 2687d62b00eSchristos user-supplied window constructor. */ 2697d62b00eSchristos 2707d62b00eSchristos class gdbpy_tui_window_maker 2717d62b00eSchristos { 2727d62b00eSchristos public: 2737d62b00eSchristos 2747d62b00eSchristos explicit gdbpy_tui_window_maker (gdbpy_ref<> &&constr) 2757d62b00eSchristos : m_constr (std::move (constr)) 2767d62b00eSchristos { 2777d62b00eSchristos } 2787d62b00eSchristos 2797d62b00eSchristos ~gdbpy_tui_window_maker (); 2807d62b00eSchristos 2817d62b00eSchristos gdbpy_tui_window_maker (gdbpy_tui_window_maker &&other) noexcept 2827d62b00eSchristos : m_constr (std::move (other.m_constr)) 2837d62b00eSchristos { 2847d62b00eSchristos } 2857d62b00eSchristos 2867d62b00eSchristos gdbpy_tui_window_maker (const gdbpy_tui_window_maker &other) 2877d62b00eSchristos { 288*6881a400Schristos gdbpy_enter enter_py; 2897d62b00eSchristos m_constr = other.m_constr; 2907d62b00eSchristos } 2917d62b00eSchristos 2927d62b00eSchristos gdbpy_tui_window_maker &operator= (gdbpy_tui_window_maker &&other) 2937d62b00eSchristos { 2947d62b00eSchristos m_constr = std::move (other.m_constr); 2957d62b00eSchristos return *this; 2967d62b00eSchristos } 2977d62b00eSchristos 2987d62b00eSchristos gdbpy_tui_window_maker &operator= (const gdbpy_tui_window_maker &other) 2997d62b00eSchristos { 300*6881a400Schristos gdbpy_enter enter_py; 3017d62b00eSchristos m_constr = other.m_constr; 3027d62b00eSchristos return *this; 3037d62b00eSchristos } 3047d62b00eSchristos 3057d62b00eSchristos tui_win_info *operator() (const char *name); 3067d62b00eSchristos 3077d62b00eSchristos private: 3087d62b00eSchristos 3097d62b00eSchristos /* A constructor that is called to make a TUI window. */ 3107d62b00eSchristos gdbpy_ref<> m_constr; 3117d62b00eSchristos }; 3127d62b00eSchristos 3137d62b00eSchristos gdbpy_tui_window_maker::~gdbpy_tui_window_maker () 3147d62b00eSchristos { 315*6881a400Schristos gdbpy_enter enter_py; 3167d62b00eSchristos m_constr.reset (nullptr); 3177d62b00eSchristos } 3187d62b00eSchristos 3197d62b00eSchristos tui_win_info * 3207d62b00eSchristos gdbpy_tui_window_maker::operator() (const char *win_name) 3217d62b00eSchristos { 322*6881a400Schristos gdbpy_enter enter_py; 3237d62b00eSchristos 3247d62b00eSchristos gdbpy_ref<gdbpy_tui_window> wrapper 3257d62b00eSchristos (PyObject_New (gdbpy_tui_window, &gdbpy_tui_window_object_type)); 3267d62b00eSchristos if (wrapper == nullptr) 3277d62b00eSchristos { 3287d62b00eSchristos gdbpy_print_stack (); 3297d62b00eSchristos return nullptr; 3307d62b00eSchristos } 3317d62b00eSchristos 3327d62b00eSchristos std::unique_ptr<tui_py_window> window 3337d62b00eSchristos (new tui_py_window (win_name, wrapper)); 3347d62b00eSchristos 3357d62b00eSchristos gdbpy_ref<> user_window 3367d62b00eSchristos (PyObject_CallFunctionObjArgs (m_constr.get (), 3377d62b00eSchristos (PyObject *) wrapper.get (), 3387d62b00eSchristos nullptr)); 3397d62b00eSchristos if (user_window == nullptr) 3407d62b00eSchristos { 3417d62b00eSchristos gdbpy_print_stack (); 3427d62b00eSchristos return nullptr; 3437d62b00eSchristos } 3447d62b00eSchristos 3457d62b00eSchristos window->set_user_window (std::move (user_window)); 3467d62b00eSchristos /* Window is now owned by the TUI. */ 3477d62b00eSchristos return window.release (); 3487d62b00eSchristos } 3497d62b00eSchristos 3507d62b00eSchristos /* Implement "gdb.register_window_type". */ 3517d62b00eSchristos 3527d62b00eSchristos PyObject * 3537d62b00eSchristos gdbpy_register_tui_window (PyObject *self, PyObject *args, PyObject *kw) 3547d62b00eSchristos { 3557d62b00eSchristos static const char *keywords[] = { "name", "constructor", nullptr }; 3567d62b00eSchristos 3577d62b00eSchristos const char *name; 3587d62b00eSchristos PyObject *cons_obj; 3597d62b00eSchristos 3607d62b00eSchristos if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "sO", keywords, 3617d62b00eSchristos &name, &cons_obj)) 3627d62b00eSchristos return nullptr; 3637d62b00eSchristos 3647d62b00eSchristos try 3657d62b00eSchristos { 3667d62b00eSchristos gdbpy_tui_window_maker constr (gdbpy_ref<>::new_reference (cons_obj)); 3677d62b00eSchristos tui_register_window (name, constr); 3687d62b00eSchristos } 3697d62b00eSchristos catch (const gdb_exception &except) 3707d62b00eSchristos { 3717d62b00eSchristos gdbpy_convert_exception (except); 3727d62b00eSchristos return nullptr; 3737d62b00eSchristos } 3747d62b00eSchristos 3757d62b00eSchristos Py_RETURN_NONE; 3767d62b00eSchristos } 3777d62b00eSchristos 3787d62b00eSchristos 3797d62b00eSchristos 3807d62b00eSchristos /* Require that "Window" be a valid window. */ 3817d62b00eSchristos 3827d62b00eSchristos #define REQUIRE_WINDOW(Window) \ 3837d62b00eSchristos do { \ 384*6881a400Schristos if (!(Window)->is_valid ()) \ 3857d62b00eSchristos return PyErr_Format (PyExc_RuntimeError, \ 3867d62b00eSchristos _("TUI window is invalid.")); \ 3877d62b00eSchristos } while (0) 3887d62b00eSchristos 389*6881a400Schristos /* Require that "Window" be a valid window. */ 390*6881a400Schristos 391*6881a400Schristos #define REQUIRE_WINDOW_FOR_SETTER(Window) \ 392*6881a400Schristos do { \ 393*6881a400Schristos if (!(Window)->is_valid ()) \ 394*6881a400Schristos { \ 395*6881a400Schristos PyErr_Format (PyExc_RuntimeError, \ 396*6881a400Schristos _("TUI window is invalid.")); \ 397*6881a400Schristos return -1; \ 398*6881a400Schristos } \ 399*6881a400Schristos } while (0) 400*6881a400Schristos 4017d62b00eSchristos /* Python function which checks the validity of a TUI window 4027d62b00eSchristos object. */ 4037d62b00eSchristos static PyObject * 4047d62b00eSchristos gdbpy_tui_is_valid (PyObject *self, PyObject *args) 4057d62b00eSchristos { 4067d62b00eSchristos gdbpy_tui_window *win = (gdbpy_tui_window *) self; 4077d62b00eSchristos 408*6881a400Schristos if (win->is_valid ()) 4097d62b00eSchristos Py_RETURN_TRUE; 4107d62b00eSchristos Py_RETURN_FALSE; 4117d62b00eSchristos } 4127d62b00eSchristos 4137d62b00eSchristos /* Python function that erases the TUI window. */ 4147d62b00eSchristos static PyObject * 4157d62b00eSchristos gdbpy_tui_erase (PyObject *self, PyObject *args) 4167d62b00eSchristos { 4177d62b00eSchristos gdbpy_tui_window *win = (gdbpy_tui_window *) self; 4187d62b00eSchristos 4197d62b00eSchristos REQUIRE_WINDOW (win); 4207d62b00eSchristos 4217d62b00eSchristos win->window->erase (); 4227d62b00eSchristos 4237d62b00eSchristos Py_RETURN_NONE; 4247d62b00eSchristos } 4257d62b00eSchristos 4267d62b00eSchristos /* Python function that writes some text to a TUI window. */ 4277d62b00eSchristos static PyObject * 4287d62b00eSchristos gdbpy_tui_write (PyObject *self, PyObject *args) 4297d62b00eSchristos { 4307d62b00eSchristos gdbpy_tui_window *win = (gdbpy_tui_window *) self; 4317d62b00eSchristos const char *text; 432*6881a400Schristos int full_window = 0; 4337d62b00eSchristos 434*6881a400Schristos if (!PyArg_ParseTuple (args, "s|i", &text, &full_window)) 4357d62b00eSchristos return nullptr; 4367d62b00eSchristos 4377d62b00eSchristos REQUIRE_WINDOW (win); 4387d62b00eSchristos 439*6881a400Schristos win->window->output (text, full_window); 4407d62b00eSchristos 4417d62b00eSchristos Py_RETURN_NONE; 4427d62b00eSchristos } 4437d62b00eSchristos 4447d62b00eSchristos /* Return the width of the TUI window. */ 4457d62b00eSchristos static PyObject * 4467d62b00eSchristos gdbpy_tui_width (PyObject *self, void *closure) 4477d62b00eSchristos { 4487d62b00eSchristos gdbpy_tui_window *win = (gdbpy_tui_window *) self; 4497d62b00eSchristos REQUIRE_WINDOW (win); 450*6881a400Schristos gdbpy_ref<> result 451*6881a400Schristos = gdb_py_object_from_longest (win->window->viewport_width ()); 452*6881a400Schristos return result.release (); 4537d62b00eSchristos } 4547d62b00eSchristos 4557d62b00eSchristos /* Return the height of the TUI window. */ 4567d62b00eSchristos static PyObject * 4577d62b00eSchristos gdbpy_tui_height (PyObject *self, void *closure) 4587d62b00eSchristos { 4597d62b00eSchristos gdbpy_tui_window *win = (gdbpy_tui_window *) self; 4607d62b00eSchristos REQUIRE_WINDOW (win); 461*6881a400Schristos gdbpy_ref<> result 462*6881a400Schristos = gdb_py_object_from_longest (win->window->viewport_height ()); 463*6881a400Schristos return result.release (); 4647d62b00eSchristos } 4657d62b00eSchristos 4667d62b00eSchristos /* Return the title of the TUI window. */ 4677d62b00eSchristos static PyObject * 4687d62b00eSchristos gdbpy_tui_title (PyObject *self, void *closure) 4697d62b00eSchristos { 4707d62b00eSchristos gdbpy_tui_window *win = (gdbpy_tui_window *) self; 4717d62b00eSchristos REQUIRE_WINDOW (win); 4727d62b00eSchristos return host_string_to_python_string (win->window->title.c_str ()).release (); 4737d62b00eSchristos } 4747d62b00eSchristos 4757d62b00eSchristos /* Set the title of the TUI window. */ 4767d62b00eSchristos static int 4777d62b00eSchristos gdbpy_tui_set_title (PyObject *self, PyObject *newvalue, void *closure) 4787d62b00eSchristos { 4797d62b00eSchristos gdbpy_tui_window *win = (gdbpy_tui_window *) self; 4807d62b00eSchristos 481*6881a400Schristos REQUIRE_WINDOW_FOR_SETTER (win); 4827d62b00eSchristos 483*6881a400Schristos if (newvalue == nullptr) 4847d62b00eSchristos { 4857d62b00eSchristos PyErr_Format (PyExc_TypeError, _("Cannot delete \"title\" attribute.")); 4867d62b00eSchristos return -1; 4877d62b00eSchristos } 4887d62b00eSchristos 4897d62b00eSchristos gdb::unique_xmalloc_ptr<char> value 4907d62b00eSchristos = python_string_to_host_string (newvalue); 4917d62b00eSchristos if (value == nullptr) 4927d62b00eSchristos return -1; 4937d62b00eSchristos 4947d62b00eSchristos win->window->title = value.get (); 4957d62b00eSchristos return 0; 4967d62b00eSchristos } 4977d62b00eSchristos 4987d62b00eSchristos static gdb_PyGetSetDef tui_object_getset[] = 4997d62b00eSchristos { 5007d62b00eSchristos { "width", gdbpy_tui_width, NULL, "Width of the window.", NULL }, 5017d62b00eSchristos { "height", gdbpy_tui_height, NULL, "Height of the window.", NULL }, 5027d62b00eSchristos { "title", gdbpy_tui_title, gdbpy_tui_set_title, "Title of the window.", 5037d62b00eSchristos NULL }, 5047d62b00eSchristos { NULL } /* Sentinel */ 5057d62b00eSchristos }; 5067d62b00eSchristos 5077d62b00eSchristos static PyMethodDef tui_object_methods[] = 5087d62b00eSchristos { 5097d62b00eSchristos { "is_valid", gdbpy_tui_is_valid, METH_NOARGS, 5107d62b00eSchristos "is_valid () -> Boolean\n\ 5117d62b00eSchristos Return true if this TUI window is valid, false if not." }, 5127d62b00eSchristos { "erase", gdbpy_tui_erase, METH_NOARGS, 5137d62b00eSchristos "Erase the TUI window." }, 5147d62b00eSchristos { "write", (PyCFunction) gdbpy_tui_write, METH_VARARGS, 5157d62b00eSchristos "Append a string to the TUI window." }, 5167d62b00eSchristos { NULL } /* Sentinel. */ 5177d62b00eSchristos }; 5187d62b00eSchristos 5197d62b00eSchristos PyTypeObject gdbpy_tui_window_object_type = 5207d62b00eSchristos { 5217d62b00eSchristos PyVarObject_HEAD_INIT (NULL, 0) 5227d62b00eSchristos "gdb.TuiWindow", /*tp_name*/ 5237d62b00eSchristos sizeof (gdbpy_tui_window), /*tp_basicsize*/ 5247d62b00eSchristos 0, /*tp_itemsize*/ 5257d62b00eSchristos 0, /*tp_dealloc*/ 5267d62b00eSchristos 0, /*tp_print*/ 5277d62b00eSchristos 0, /*tp_getattr*/ 5287d62b00eSchristos 0, /*tp_setattr*/ 5297d62b00eSchristos 0, /*tp_compare*/ 5307d62b00eSchristos 0, /*tp_repr*/ 5317d62b00eSchristos 0, /*tp_as_number*/ 5327d62b00eSchristos 0, /*tp_as_sequence*/ 5337d62b00eSchristos 0, /*tp_as_mapping*/ 5347d62b00eSchristos 0, /*tp_hash */ 5357d62b00eSchristos 0, /*tp_call*/ 5367d62b00eSchristos 0, /*tp_str*/ 5377d62b00eSchristos 0, /*tp_getattro*/ 5387d62b00eSchristos 0, /*tp_setattro */ 5397d62b00eSchristos 0, /*tp_as_buffer*/ 5407d62b00eSchristos Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 5417d62b00eSchristos "GDB TUI window object", /* tp_doc */ 5427d62b00eSchristos 0, /* tp_traverse */ 5437d62b00eSchristos 0, /* tp_clear */ 5447d62b00eSchristos 0, /* tp_richcompare */ 5457d62b00eSchristos 0, /* tp_weaklistoffset */ 5467d62b00eSchristos 0, /* tp_iter */ 5477d62b00eSchristos 0, /* tp_iternext */ 5487d62b00eSchristos tui_object_methods, /* tp_methods */ 5497d62b00eSchristos 0, /* tp_members */ 5507d62b00eSchristos tui_object_getset, /* tp_getset */ 5517d62b00eSchristos 0, /* tp_base */ 5527d62b00eSchristos 0, /* tp_dict */ 5537d62b00eSchristos 0, /* tp_descr_get */ 5547d62b00eSchristos 0, /* tp_descr_set */ 5557d62b00eSchristos 0, /* tp_dictoffset */ 5567d62b00eSchristos 0, /* tp_init */ 5577d62b00eSchristos 0, /* tp_alloc */ 5587d62b00eSchristos }; 5597d62b00eSchristos 5607d62b00eSchristos #endif /* TUI */ 5617d62b00eSchristos 5627d62b00eSchristos /* Initialize this module. */ 5637d62b00eSchristos 5647d62b00eSchristos int 5657d62b00eSchristos gdbpy_initialize_tui () 5667d62b00eSchristos { 5677d62b00eSchristos #ifdef TUI 5687d62b00eSchristos gdbpy_tui_window_object_type.tp_new = PyType_GenericNew; 5697d62b00eSchristos if (PyType_Ready (&gdbpy_tui_window_object_type) < 0) 5707d62b00eSchristos return -1; 5717d62b00eSchristos #endif /* TUI */ 5727d62b00eSchristos 5737d62b00eSchristos return 0; 5747d62b00eSchristos } 575