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.

297 lines
7.9KB

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