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.

284 lines
7.6KB

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