GuiWindow.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /* GuiWindow.cpp
  2. *
  3. * Copyright (C) 1993-2012,2013,2014,2015,2016,2017 Paul Boersma, 2013 Tom Naughton
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "GuiP.h"
  19. #include "../kar/UnicodeData.h"
  20. #include "machine.h"
  21. #include <locale.h>
  22. Thing_implement (GuiWindow, GuiShell, 0);
  23. #undef iam
  24. #define iam(x) x me = (x) void_me
  25. #if gtk
  26. static gboolean _GuiWindow_destroyCallback (GuiObject widget, GdkEvent *event, gpointer void_me) {
  27. (void) widget;
  28. iam (GuiWindow);
  29. forget (me);
  30. return true;
  31. }
  32. static gboolean _GuiWindow_goAwayCallback (GuiObject widget, GdkEvent *event, gpointer void_me) {
  33. (void) widget;
  34. iam (GuiWindow);
  35. if (my d_goAwayCallback) {
  36. my d_goAwayCallback (my d_goAwayBoss);
  37. }
  38. return true;
  39. }
  40. static void _GuiWindow_child_resizeCallback (GtkWidget *childWidget, gpointer data) {
  41. GtkAllocation *allocation = (GtkAllocation *) data;
  42. GtkWidget *parentWidget = gtk_widget_get_parent (childWidget);
  43. Thing_cast (GuiThing, child, _GuiObject_getUserData (childWidget));
  44. if (child) {
  45. GuiControl control = nullptr;
  46. if (Thing_isa (child, classGuiControl)) {
  47. control = static_cast <GuiControl> (child);
  48. } else if (Thing_isa (child, classGuiMenu)) {
  49. Thing_cast (GuiMenu, menu, child);
  50. control = menu -> d_cascadeButton.get();
  51. }
  52. if (control) {
  53. /*
  54. * Move and resize.
  55. */
  56. trace (U"moving child of class ", Thing_className (control));
  57. int left = control -> d_left, right = control -> d_right, top = control -> d_top, bottom = control -> d_bottom;
  58. if (left < 0) left += allocation -> width; // this replicates structGuiControl :: v_positionInForm ()
  59. if (right <= 0) right += allocation -> width;
  60. if (top < 0) top += allocation -> height;
  61. if (bottom <= 0) bottom += allocation -> height;
  62. trace (U"moving child to (", left, U",", top, U")");
  63. gtk_fixed_move (GTK_FIXED (parentWidget), GTK_WIDGET (childWidget), left, top);
  64. gtk_widget_set_size_request (GTK_WIDGET (childWidget), right - left, bottom - top);
  65. trace (U"moved child of class ", Thing_className (control));
  66. }
  67. }
  68. }
  69. static gboolean _GuiWindow_resizeCallback (GuiObject widget, GtkAllocation *allocation, gpointer void_me) {
  70. (void) widget;
  71. iam (GuiWindow);
  72. trace (U"fixed received size allocation: (", allocation -> x, U", ", allocation -> y,
  73. U"), ", allocation -> width, U" x ", allocation -> height, U".");
  74. if (allocation -> width != my d_width || allocation -> height != my d_height) {
  75. trace (U"user changed the size of the window?");
  76. /*
  77. * Apparently, GTK sends the size allocation message both to the shell and to its fixed-container child.
  78. * we could capture the message either from the shell or from the fixed; we choose to do it from the fixed.
  79. */
  80. Melder_assert (GTK_IS_FIXED (widget));
  81. /*
  82. * We move and resize all the children of the fixed.
  83. */
  84. gtk_container_foreach (GTK_CONTAINER (widget), _GuiWindow_child_resizeCallback, allocation);
  85. my d_width = allocation -> width;
  86. my d_height = allocation -> height;
  87. gtk_widget_set_size_request (GTK_WIDGET (widget), allocation -> width, allocation -> height);
  88. }
  89. trace (U"end");
  90. return false;
  91. }
  92. #elif motif
  93. static void _GuiMotifWindow_destroyCallback (GuiObject widget, XtPointer void_me, XtPointer call) {
  94. (void) widget; (void) call;
  95. iam (GuiWindow);
  96. if (my d_xmMenuBar) {
  97. }
  98. trace (U"destroying window widget");
  99. forget (me);
  100. }
  101. static void _GuiMotifWindow_goAwayCallback (GuiObject widget, XtPointer void_me, XtPointer call) {
  102. (void) widget; (void) call;
  103. iam (GuiWindow);
  104. if (my d_goAwayCallback) {
  105. //Melder_casual (U"_GuiMotifWindow_goAwayCallback: before");
  106. my d_goAwayCallback (my d_goAwayBoss);
  107. //Melder_casual (U"_GuiMotifWindow_goAwayCallback: after");
  108. }
  109. }
  110. #endif
  111. GuiWindow GuiWindow_create (int x, int y, int width, int height, int minimumWidth, int minimumHeight,
  112. conststring32 title /* cattable */, GuiShell_GoAwayCallback goAwayCallback, Thing goAwayBoss, uint32 flags)
  113. {
  114. autoGuiWindow me = Thing_new (GuiWindow);
  115. my d_parent = nullptr;
  116. my d_goAwayCallback = goAwayCallback;
  117. my d_goAwayBoss = goAwayBoss;
  118. #if gtk
  119. (void) flags;
  120. GuiGtk_initialize ();
  121. my d_gtkWindow = (GtkWindow *) gtk_window_new (GTK_WINDOW_TOPLEVEL);
  122. g_signal_connect (G_OBJECT (my d_gtkWindow), "delete-event", goAwayCallback ? G_CALLBACK (_GuiWindow_goAwayCallback) : G_CALLBACK (gtk_widget_hide), me.get());
  123. g_signal_connect (G_OBJECT (my d_gtkWindow), "destroy-event", G_CALLBACK (_GuiWindow_destroyCallback), me.get());
  124. gtk_window_set_default_size (GTK_WINDOW (my d_gtkWindow), width, height);
  125. gtk_window_set_resizable (GTK_WINDOW (my d_gtkWindow), true);
  126. GuiShell_setTitle (me.get(), title);
  127. my d_widget = gtk_fixed_new ();
  128. _GuiObject_setUserData (my d_widget, me.get());
  129. gtk_widget_set_size_request (GTK_WIDGET (my d_widget), width, height);
  130. gtk_container_add (GTK_CONTAINER (my d_gtkWindow), GTK_WIDGET (my d_widget));
  131. GdkGeometry geometry = { minimumWidth, minimumHeight, 0, 0, 0, 0, 0, 0, 0, 0, GDK_GRAVITY_NORTH_WEST };
  132. gtk_window_set_geometry_hints (my d_gtkWindow, GTK_WIDGET (my d_gtkWindow), & geometry, GDK_HINT_MIN_SIZE);
  133. g_signal_connect (G_OBJECT (my d_widget), "size-allocate", G_CALLBACK (_GuiWindow_resizeCallback), me.get());
  134. #elif motif
  135. my d_xmShell = XmCreateShell (nullptr, flags & GuiWindow_FULLSCREEN ? "Praatwulgfullscreen" : "Praatwulg", nullptr, 0);
  136. XtVaSetValues (my d_xmShell, XmNdeleteResponse, goAwayCallback ? XmDO_NOTHING : XmUNMAP, nullptr);
  137. XtVaSetValues (my d_xmShell, XmNx, x, XmNy, y, XmNwidth, (Dimension) width, XmNheight, (Dimension) height, nullptr);
  138. if (goAwayCallback) {
  139. XmAddWMProtocolCallback (my d_xmShell, 'delw', _GuiMotifWindow_goAwayCallback, (char *) me.get());
  140. }
  141. GuiShell_setTitle (me.get(), title);
  142. my d_widget = XmCreateForm (my d_xmShell, "dialog", nullptr, 0);
  143. _GuiObject_setUserData (my d_widget, me.get());
  144. XtAddCallback (my d_widget, XmNdestroyCallback, _GuiMotifWindow_destroyCallback, me.get());
  145. XtVaSetValues (my d_widget, XmNdialogStyle, XmDIALOG_MODELESS, XmNautoUnmanage, False, nullptr);
  146. #elif cocoa
  147. (void) flags;
  148. NSRect rect = { { static_cast<CGFloat>(x), static_cast<CGFloat>(y) }, { static_cast<CGFloat>(width), static_cast<CGFloat>(height) } };
  149. my d_cocoaShell = [[GuiCocoaShell alloc]
  150. initWithContentRect: rect
  151. styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask
  152. backing: NSBackingStoreBuffered
  153. defer: false];
  154. [my d_cocoaShell setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
  155. [my d_cocoaShell setMinSize: NSMakeSize (minimumWidth, minimumHeight)];
  156. GuiShell_setTitle (me.get(), title);
  157. [my d_cocoaShell makeKeyAndOrderFront: nil];
  158. my d_widget = (GuiObject) [my d_cocoaShell contentView]; // BUG: this d_widget doesn't have the GuiCocoaAny protocol
  159. _GuiObject_setUserData (my d_cocoaShell, me.get());
  160. //if (! theGuiCocoaWindowDelegate) {
  161. // theGuiCocoaWindowDelegate = [[GuiCocoaWindowDelegate alloc] init];
  162. //}
  163. //[my d_cocoaWindow setDelegate: theGuiCocoaWindowDelegate];
  164. #endif
  165. my d_width = width;
  166. my d_height = height;
  167. my d_shell = me.get();
  168. return me.releaseToAmbiguousOwner();
  169. }
  170. uinteger theGuiTopLowAccelerators [8];
  171. void GuiWindow_addMenuBar (GuiWindow me) {
  172. #if gtk
  173. my d_gtkMenuBar = (GtkMenuBar *) gtk_menu_bar_new ();
  174. _GuiObject_setUserData (my d_gtkMenuBar, me);
  175. my v_positionInForm (my d_gtkMenuBar, 0, 0, 0, Machine_getMenuBarHeight (), me); // BUG?
  176. // we need an accelerator group for each window we're creating accelerated menus on
  177. GuiObject topwin = gtk_widget_get_toplevel (GTK_WIDGET (my d_widget));
  178. Melder_assert (topwin == my d_gtkWindow);
  179. GtkAccelGroup *ag = gtk_accel_group_new ();
  180. gtk_window_add_accel_group (GTK_WINDOW (topwin), ag);
  181. // unfortunately, menu-bars don't fiddle with accel-groups, so we need a way
  182. // to pass it to the sub-menus created upon this bar for their items to have
  183. // access to the accel-group
  184. g_object_set_data (G_OBJECT (my d_gtkMenuBar), "accel-group", ag);
  185. gtk_widget_show (GTK_WIDGET (my d_gtkMenuBar));
  186. #elif motif
  187. my d_xmMenuBar = XmCreateMenuBar (my d_widget, "menuBar", nullptr, 0);
  188. XtVaSetValues (my d_xmMenuBar, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, nullptr);
  189. XtManageChild (my d_xmMenuBar);
  190. #elif cocoa
  191. #endif
  192. }
  193. bool GuiWindow_setDirty (GuiWindow me, bool dirty) {
  194. #if gtk
  195. (void) dirty;
  196. return false;
  197. #elif motif
  198. (void) dirty;
  199. return false;
  200. #elif cocoa
  201. [my d_cocoaShell setDocumentEdited: dirty];
  202. return true;
  203. #else
  204. (void) dirty;
  205. return false;
  206. #endif
  207. }
  208. /* End of file GuiWindow.cpp */