xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/python/py-tui.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
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