Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
7.9KB

  1. /*
  2. * Carla Bridge Toolkit, Gtk version
  3. * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program 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
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaBridgeUI.hpp"
  18. #include <gtk/gtk.h>
  19. #if defined(CARLA_OS_LINUX) && defined(HAVE_X11)
  20. # define USE_CUSTOM_X11_METHODS
  21. # include <gdk/gdkx.h>
  22. #endif
  23. CARLA_BRIDGE_START_NAMESPACE
  24. // -------------------------------------------------------------------------
  25. static int gargc = 0;
  26. static char** gargv = nullptr;
  27. static const bool gHideShowTesting = std::getenv("CARLA_UI_TESTING") != nullptr;
  28. // -------------------------------------------------------------------------
  29. class CarlaBridgeToolkitGtk : public CarlaBridgeToolkit
  30. {
  31. public:
  32. CarlaBridgeToolkitGtk(CarlaBridgeUI* const u)
  33. : CarlaBridgeToolkit(u),
  34. fNeedsShow(false),
  35. fWindow(nullptr),
  36. fLastX(0),
  37. fLastY(0),
  38. fLastWidth(0),
  39. fLastHeight(0),
  40. leakDetector_CarlaBridgeToolkitGtk()
  41. {
  42. carla_debug("CarlaBridgeToolkitGtk::CarlaBridgeToolkitGtk(%p)", u);
  43. }
  44. ~CarlaBridgeToolkitGtk() override
  45. {
  46. CARLA_SAFE_ASSERT(fWindow == nullptr);
  47. carla_debug("CarlaBridgeToolkitGtk::~CarlaBridgeToolkitGtk()");
  48. }
  49. bool init(const int /*argc*/, const char** /*argv[]*/) override
  50. {
  51. CARLA_SAFE_ASSERT_RETURN(fWindow == nullptr, false);
  52. carla_debug("CarlaBridgeToolkitGtk::init()");
  53. gtk_init(&gargc, &gargv);
  54. fWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  55. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr, false);
  56. gtk_window_resize(GTK_WINDOW(fWindow), 30, 30);
  57. gtk_widget_hide(fWindow);
  58. return true;
  59. }
  60. void exec(const bool showUI) override
  61. {
  62. CARLA_SAFE_ASSERT_RETURN(ui != nullptr,);
  63. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,);
  64. carla_debug("CarlaBridgeToolkitGtk::exec(%s)", bool2str(showUI));
  65. const CarlaBridgeUI::Options& options(ui->getOptions());
  66. GtkWindow* const gtkWindow(GTK_WINDOW(fWindow));
  67. CARLA_SAFE_ASSERT_RETURN(gtkWindow != nullptr,);
  68. GtkWidget* const widget((GtkWidget*)ui->getWidget());
  69. gtk_container_add(GTK_CONTAINER(fWindow), widget);
  70. gtk_window_set_resizable(gtkWindow, options.isResizable);
  71. gtk_window_set_title(gtkWindow, options.windowTitle.buffer());
  72. if (showUI || fNeedsShow)
  73. {
  74. show();
  75. fNeedsShow = false;
  76. }
  77. g_timeout_add(30, gtk_ui_timeout, this);
  78. g_signal_connect(fWindow, "destroy", G_CALLBACK(gtk_ui_destroy), this);
  79. g_signal_connect(fWindow, "realize", G_CALLBACK(gtk_ui_realize), this);
  80. // First idle
  81. handleTimeout();
  82. // Main loop
  83. gtk_main();
  84. }
  85. void quit() override
  86. {
  87. carla_debug("CarlaBridgeToolkitGtk::quit()");
  88. if (fWindow != nullptr)
  89. {
  90. gtk_widget_destroy(fWindow);
  91. fWindow = nullptr;
  92. gtk_main_quit_if_needed();
  93. }
  94. }
  95. void show() override
  96. {
  97. carla_debug("CarlaBridgeToolkitGtk::show()");
  98. fNeedsShow = true;
  99. if (fWindow != nullptr)
  100. gtk_widget_show_all(fWindow);
  101. }
  102. void focus() override
  103. {
  104. carla_debug("CarlaBridgeToolkitGtk::focus()");
  105. }
  106. void hide() override
  107. {
  108. carla_debug("CarlaBridgeToolkitGtk::hide()");
  109. fNeedsShow = false;
  110. if (fWindow != nullptr)
  111. gtk_widget_hide(fWindow);
  112. }
  113. void setSize(const uint width, const uint height) override
  114. {
  115. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,);
  116. carla_debug("CarlaBridgeToolkitGtk::resize(%i, %i)", width, height);
  117. gtk_window_resize(GTK_WINDOW(fWindow), width, height);
  118. }
  119. void setTitle(const char* const title) override
  120. {
  121. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,);
  122. carla_debug("CarlaBridgeToolkitGtk::setTitle(\"%s\")", title);
  123. gtk_window_set_title(GTK_WINDOW(fWindow), title);
  124. }
  125. // ---------------------------------------------------------------------
  126. protected:
  127. bool fNeedsShow;
  128. GtkWidget* fWindow;
  129. gint fLastX;
  130. gint fLastY;
  131. gint fLastWidth;
  132. gint fLastHeight;
  133. void handleDestroy()
  134. {
  135. carla_debug("CarlaBridgeToolkitGtk::handleDestroy()");
  136. fWindow = nullptr;
  137. }
  138. void handleRealize()
  139. {
  140. carla_debug("CarlaBridgeToolkitGtk::handleRealize()");
  141. const CarlaBridgeUI::Options& options(ui->getOptions());
  142. if (options.transientWindowId != 0)
  143. setTransient(options.transientWindowId);
  144. }
  145. gboolean handleTimeout()
  146. {
  147. if (fWindow != nullptr)
  148. {
  149. gtk_window_get_position(GTK_WINDOW(fWindow), &fLastX, &fLastY);
  150. gtk_window_get_size(GTK_WINDOW(fWindow), &fLastWidth, &fLastHeight);
  151. }
  152. if (ui->isPipeRunning())
  153. ui->idlePipe();
  154. ui->idleUI();
  155. if (gHideShowTesting)
  156. {
  157. static int counter = 0;
  158. ++counter;
  159. if (counter == 100)
  160. {
  161. hide();
  162. }
  163. else if (counter == 200)
  164. {
  165. show();
  166. counter = 0;
  167. }
  168. }
  169. return true;
  170. }
  171. void setTransient(const uintptr_t winId)
  172. {
  173. CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,);
  174. carla_debug("CarlaBridgeToolkitGtk::setTransient(0x" P_UINTPTR ")", winId);
  175. #ifdef USE_CUSTOM_X11_METHODS
  176. GdkWindow* const gdkWindow(gtk_widget_get_window(fWindow));
  177. CARLA_SAFE_ASSERT_RETURN(gdkWindow != nullptr,);
  178. # ifdef BRIDGE_GTK3
  179. GdkDisplay* const gdkDisplay(gdk_window_get_display(gdkWindow));
  180. CARLA_SAFE_ASSERT_RETURN(gdkDisplay != nullptr,);
  181. ::Display* const display(gdk_x11_display_get_xdisplay(gdkDisplay));
  182. CARLA_SAFE_ASSERT_RETURN(display != nullptr,);
  183. const ::XID xid(gdk_x11_window_get_xid(gdkWindow));
  184. CARLA_SAFE_ASSERT_RETURN(xid != 0,);
  185. # else
  186. ::Display* const display(gdk_x11_drawable_get_xdisplay(gdkWindow));
  187. CARLA_SAFE_ASSERT_RETURN(display != nullptr,);
  188. const ::XID xid(gdk_x11_drawable_get_xid(gdkWindow));
  189. CARLA_SAFE_ASSERT_RETURN(xid != 0,);
  190. # endif
  191. XSetTransientForHint(display, xid, static_cast< ::Window>(winId));
  192. #endif
  193. }
  194. // ---------------------------------------------------------------------
  195. private:
  196. static void gtk_main_quit_if_needed()
  197. {
  198. if (gtk_main_level() != 0)
  199. gtk_main_quit();
  200. }
  201. static void gtk_ui_destroy(GtkWidget*, gpointer data)
  202. {
  203. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  204. ((CarlaBridgeToolkitGtk*)data)->handleDestroy();
  205. gtk_main_quit_if_needed();
  206. }
  207. static void gtk_ui_realize(GtkWidget*, gpointer data)
  208. {
  209. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  210. ((CarlaBridgeToolkitGtk*)data)->handleRealize();
  211. }
  212. static gboolean gtk_ui_timeout(gpointer data)
  213. {
  214. CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
  215. return ((CarlaBridgeToolkitGtk*)data)->handleTimeout();
  216. }
  217. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaBridgeToolkitGtk)
  218. };
  219. // -------------------------------------------------------------------------
  220. CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeUI* const ui)
  221. {
  222. return new CarlaBridgeToolkitGtk(ui);
  223. }
  224. // -------------------------------------------------------------------------
  225. CARLA_BRIDGE_END_NAMESPACE