extension.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* jshint esnext:true */
  2. const Clutter = imports.gi.Clutter;
  3. const GLib = imports.gi.GLib;
  4. const Main = imports.ui.main;
  5. const Mainloop = imports.mainloop;
  6. const MAX_RECURSE_DEPTH = 3;
  7. let signalConnections = [];
  8. let dropdowns = [];
  9. /**
  10. * Try hide a single dropdown actor.
  11. *
  12. * Return true on success.
  13. */
  14. function _apply(actor)
  15. {
  16. if (!actor.has_style_class_name || !actor.has_style_class_name('popup-menu-arrow'))
  17. {
  18. return false;
  19. }
  20. actor.hide();
  21. if (dropdowns.indexOf(actor) < 0)
  22. {
  23. let connection = {
  24. object: actor,
  25. id: actor.connect('destroy', function()
  26. {
  27. let index;
  28. index = signalConnections.indexOf(connection);
  29. if (index >= 0)
  30. {
  31. signalConnections.splice(index, 1);
  32. }
  33. index = dropdowns.indexOf(actor);
  34. if (index >= 0)
  35. {
  36. dropdowns.splice(index, 1);
  37. }
  38. })
  39. };
  40. signalConnections.push(connection);
  41. dropdowns.push(actor);
  42. }
  43. return true;
  44. }
  45. /**
  46. * Similar function to _recursiveApply(), but intended for containers.
  47. */
  48. function _recursiveApplyInternal(actor, depth)
  49. {
  50. if (typeof actor.get_children === 'undefined')
  51. {
  52. return false;
  53. }
  54. let children = actor.get_children();
  55. // If there are no children then it's possible that actor hasn't been fully initialized yet.
  56. // Shedule to check later.
  57. if (children.length == 0)
  58. {
  59. _scheduleApply(actor);
  60. return false;
  61. }
  62. // Check actor immediate children before using recursion
  63. if (children.map(child => _apply(child)).indexOf(true) >= 0)
  64. {
  65. return true;
  66. }
  67. // Check children recursively
  68. if (depth < MAX_RECURSE_DEPTH)
  69. {
  70. if (children.map(child => _recursiveApplyInternal(child, depth +1)).indexOf(true) >= 0)
  71. {
  72. return true;
  73. }
  74. }
  75. return false;
  76. }
  77. function _scheduleApply(actor)
  78. {
  79. let actorAddedId, destroyId, timeoutId;
  80. actorAddedId = actor.connect('actor-added', function(child)
  81. {
  82. if (_recursiveApply(child))
  83. {
  84. actor.disconnect(actorAddedId);
  85. actor.disconnect(destroyId);
  86. Mainloop.source_remove(timeoutId);
  87. actorAddedId = destroyId = timeoutId = 0;
  88. }
  89. });
  90. destroyId = actor.connect('destroy', function()
  91. {
  92. if (timeoutId != 0) {
  93. Mainloop.source_remove(timeoutId);
  94. timeoutId = 0;
  95. }
  96. });
  97. timeoutId = Mainloop.idle_add(function()
  98. {
  99. actor.disconnect(actorAddedId);
  100. actor.disconnect(destroyId);
  101. actorAddedId = destroyId = timeoutId = 0;
  102. return GLib.SOURCE_REMOVE;
  103. });
  104. }
  105. function _recursiveApply(actor)
  106. {
  107. return _apply(actor) || _recursiveApplyInternal(actor, 0);
  108. }
  109. function init()
  110. {
  111. // no initialization required
  112. }
  113. function enable()
  114. {
  115. let panelActor = Main.panel instanceof Clutter.Actor ? Main.panel : Main.panel.actor;
  116. panelActor.get_children().forEach(
  117. function(actor)
  118. {
  119. signalConnections.push({
  120. object: actor,
  121. id: actor.connect('actor-added', _recursiveApply)
  122. });
  123. actor.get_children().forEach(_recursiveApply);
  124. });
  125. }
  126. function disable()
  127. {
  128. while (signalConnections.length > 0)
  129. {
  130. let connection = signalConnections.pop();
  131. connection.object.disconnect(connection.id);
  132. }
  133. while (dropdowns.length > 0)
  134. {
  135. let actor = dropdowns.pop();
  136. actor.show();
  137. }
  138. }