diff --git a/src/buddies/src/bd/strmrun.cc b/src/buddies/src/bd/strmrun.cc index dac4a9981..92b522afa 100644 --- a/src/buddies/src/bd/strmrun.cc +++ b/src/buddies/src/bd/strmrun.cc @@ -35,6 +35,7 @@ #include "libForceLink.h" #include "rdbForceLink.h" #include "lymMacro.h" +#include "lymMacroCollection.h" struct RunnerData { @@ -83,7 +84,13 @@ BD_PUBLIC int strmrun (int argc, char *argv[]) python.define_variable (v->first, v->second); } - // @@@ ... add Python and Ruby built-in macro collections, autorun-early and autorun ... + // install the built-in macros so we can run DRC and LVS scripts + lym::MacroCollection &lym_root = lym::MacroCollection::root (); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-macros", "macros", true); + lym_root.add_folder (tl::to_string (tr ("Built-In")), ":/built-in-pymacros", "pymacros", true); + + lym_root.autorun_early (); + lym_root.autorun (); std::string script = tl::absolute_file_path (data.script); diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 35293190d..16f2caffb 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -392,7 +392,7 @@ HEADERS = \ dbShapeCollection.h \ dbShapeCollectionUtils.h -!equals(HAVE_QT, "0") { +!equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { RESOURCES = \ dbResources.qrc \ diff --git a/src/db/db/dbGlyphs.cc b/src/db/db/dbGlyphs.cc index 362de0dd2..a61c9722e 100644 --- a/src/db/db/dbGlyphs.cc +++ b/src/db/db/dbGlyphs.cc @@ -147,20 +147,11 @@ TextGenerator::text_as_region (const std::string &t, double target_dbu, double m return region; } -#if defined(HAVE_QT) void TextGenerator::load_from_resource (const std::string &name) { - QResource res (tl::to_qstring (name)); - if (res.size () == 0) { - throw tl::Exception (tl::to_string (tr ("Unable to load font resource from ")) + name); - } - - QByteArray data = qUncompress (QByteArray ((const char *) res.data (), int (res.size ()))); - - load_from_data (data.constData (), data.size (), tl::to_string (QFileInfo (tl::to_qstring (name)).baseName ()), name); + load_from_file (name); } -#endif void TextGenerator::load_from_data (const char *data, size_t ndata, const std::string &name, const std::string &description) diff --git a/src/db/db/dbGlyphs.h b/src/db/db/dbGlyphs.h index a3073984f..c42e186fd 100644 --- a/src/db/db/dbGlyphs.h +++ b/src/db/db/dbGlyphs.h @@ -76,12 +76,10 @@ public: */ TextGenerator (); -#if defined(HAVE_QT) /** * @brief Loads the font from the given resource */ void load_from_resource (const std::string &name); -#endif /** * @brief Loads from the given binary data diff --git a/src/db/db/gsiDeclDbGlyphs.cc b/src/db/db/gsiDeclDbGlyphs.cc index 95f2fd02e..f471f79d9 100644 --- a/src/db/db/gsiDeclDbGlyphs.cc +++ b/src/db/db/gsiDeclDbGlyphs.cc @@ -65,12 +65,11 @@ static std::vector generators () } Class decl_TextGenerator ("db", "TextGenerator", -#if defined(HAVE_QT) method ("load_from_resource", &db::TextGenerator::load_from_resource, arg ("resource_path"), "@brief Loads the given resource data (as layout data) into the generator\n" + "The resource path has to start with a colon, i.e. ':/my/resource.gds'. " "See the description of the class how the layout data is read." ) + -#endif method ("load_from_file", &db::TextGenerator::load_from_file, arg ("path"), "@brief Loads the given file into the generator\n" "See the description of the class how the layout data is read." diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index bde1c2ee7..8432a1890 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -3265,6 +3265,15 @@ CODE self.data.is_a?(RBA::EdgePairs) end + # %DRC% + # @name texts? + # @brief Returns true, if the layer is a text collection + # @synopsis layer.texts? + + def texts? + self.data.is_a?(RBA::Texts) + end + # %DRC% # @name is_deep? # @brief Returns true, if the layer is a deep (hierarchical) layer diff --git a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc index 7af7cdc21..84ad80b9a 100644 --- a/src/layview/layview/gsiDeclLayLayoutView_noqt.cc +++ b/src/layview/layview/gsiDeclLayLayoutView_noqt.cc @@ -96,56 +96,6 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This object controls these aspects of the view and controls the appearance of the data. " ); -static lay::CellViewRef get_active_cellview_ref () -{ - lay::LayoutView *view = 0; // @@@ lay::LayoutView::current (); - if (! view) { - return lay::CellViewRef (); - } - if (view->active_cellview_index () >= 0) { - return view->active_cellview_ref (); - } else { - return lay::CellViewRef (); - } -} - -static lay::LayoutView *get_view (lay::CellViewRef *cv) -{ - return cv->view ()->ui (); -} - -static ClassExt extdecl_CellView ( - method ("active", &get_active_cellview_ref, - "@brief Gets the active CellView\n" - "The active CellView is the one that is selected in the current layout view. This method is " - "equivalent to\n" - "@code\n" - "RBA::LayoutView::current.active_cellview\n" - "@/code\n" - "If no CellView is active, this method returns nil.\n" - "\n" - "This method has been introduced in version 0.23." - ) + - method_ext ("view", &get_view, - "@brief Gets the view the cellview resides in\n" - "This reference will be nil if the cellview is not a valid one.\n" - "This method has been added in version 0.25.\n" - ) -); - -static lay::LayoutView *get_view_from_lp (lay::LayerPropertiesNode *node) -{ - return node->view ()->ui (); -} - -static ClassExt extdecl_LayerPropertiesNode ( - method_ext ("view", &get_view_from_lp, - "@brief Gets the view this node lives in\n" - "\n" - "This reference can be nil if the node is a orphan node that lives outside a view." - ) -); - } #endif diff --git a/src/layview/layview/gsiDeclLayLayoutView_qt.cc b/src/layview/layview/gsiDeclLayLayoutView_qt.cc index 4a86add4b..8f104d62f 100644 --- a/src/layview/layview/gsiDeclLayLayoutView_qt.cc +++ b/src/layview/layview/gsiDeclLayLayoutView_qt.cc @@ -171,56 +171,6 @@ Class decl_LayoutView (decl_LayoutViewBase, "lay", "LayoutView" "This object controls these aspects of the view and controls the appearance of the data. " ); -static lay::CellViewRef get_active_cellview_ref () -{ - lay::LayoutView *view = lay::LayoutView::current (); - if (! view) { - return lay::CellViewRef (); - } - if (view->active_cellview_index () >= 0) { - return view->active_cellview_ref (); - } else { - return lay::CellViewRef (); - } -} - -static lay::LayoutView *get_view (lay::CellViewRef *cv) -{ - return cv->view ()->ui (); -} - -static ClassExt extdecl_CellView ( - method ("active", &get_active_cellview_ref, - "@brief Gets the active CellView\n" - "The active CellView is the one that is selected in the current layout view. This method is " - "equivalent to\n" - "@code\n" - "RBA::LayoutView::current.active_cellview\n" - "@/code\n" - "If no CellView is active, this method returns nil.\n" - "\n" - "This method has been introduced in version 0.23." - ) + - method_ext ("view", &get_view, - "@brief Gets the view the cellview resides in\n" - "This reference will be nil if the cellview is not a valid one.\n" - "This method has been added in version 0.25.\n" - ) -); - -static lay::LayoutView *get_view_from_lp (lay::LayerPropertiesNode *node) -{ - return node->view ()->ui (); -} - -static ClassExt extdecl_LayerPropertiesNode ( - method_ext ("view", &get_view_from_lp, - "@brief Gets the view this node lives in\n" - "\n" - "This reference can be nil if the node is a orphan node that lives outside a view." - ) -); - } #endif diff --git a/src/layview/layview/layview.pro b/src/layview/layview/layview.pro index 30d92982f..4fd39c63e 100644 --- a/src/layview/layview/layview.pro +++ b/src/layview/layview/layview.pro @@ -11,6 +11,7 @@ RESOURCES = \ SOURCES = \ layGridNet.cc \ layviewForceLink.cc \ + gsiDeclLayAdditional.cc \ HEADERS = \ layGridNet.h \ diff --git a/src/lib_ut.pri b/src/lib_ut.pri index e80c7ba32..c54e5aac3 100644 --- a/src/lib_ut.pri +++ b/src/lib_ut.pri @@ -17,8 +17,10 @@ win32 { QMAKE_POST_LINK += $(COPY) $(DESTDIR)$(TARGET) $$DESTDIR_UT/$${TARGET}.ut } -greaterThan(QT_MAJOR_VERSION, 4) { - QT += testlib -} else { - CONFIG += qtestlib +!equals(HAVE_QT, "0") { + greaterThan(QT_MAJOR_VERSION, 4) { + QT += testlib + } else { + CONFIG += qtestlib + } } diff --git a/src/rba/unit_tests/unit_tests.qrc b/src/rba/unit_tests/rba_unit_tests.qrc similarity index 100% rename from src/rba/unit_tests/unit_tests.qrc rename to src/rba/unit_tests/rba_unit_tests.qrc diff --git a/src/rba/unit_tests/unit_tests.pro b/src/rba/unit_tests/unit_tests.pro index 26a48aed4..6bca18f2f 100644 --- a/src/rba/unit_tests/unit_tests.pro +++ b/src/rba/unit_tests/unit_tests.pro @@ -14,7 +14,7 @@ DEPENDPATH += $$RBA_INC $$TL_INC $$DB_INC $$GSI_INC LIBS += -L$$DESTDIR_UT -lklayout_rba -lklayout_tl -lklayout_db -lklayout_gsi -!equals(HAVE_QT, "0") { +!equals(HAVE_QT, "0") || !equals(HAVE_PYTHON, "0") { RESOURCES = \ - unit_tests.qrc + rba_unit_tests.qrc } diff --git a/testdata/ruby/dbLayoutTest.rb b/testdata/ruby/dbLayoutTest.rb index 29a7f3dc2..d45f27249 100644 --- a/testdata/ruby/dbLayoutTest.rb +++ b/testdata/ruby/dbLayoutTest.rb @@ -310,12 +310,8 @@ class DBLayoutTest_TestClass < TestBase assert_equal( inst.nb, 20 ) assert_equal( inst.cell_index, c1.cell_index ) - if( RBA::Application::instance.is_editable? ) - c2.each_inst { |inst| c2.erase( inst ) } - assert_equal( c2.bbox.to_s, "()" ) - else - c2.clear_insts - end + c2.each_inst { |inst| c2.erase( inst ) } + assert_equal( c2.bbox.to_s, "()" ) tr = RBA::CplxTrans::new( 1.5, 90.0, true, RBA::DPoint::new( 100, -50 ) ) inst = RBA::CellInstArray::new( c1.cell_index, tr, RBA::Point::new( 100, 0 ), RBA::Point::new( 0, 100 ), 10, 20 ) @@ -555,12 +551,7 @@ class DBLayoutTest_TestClass < TestBase assert_equal( inst.nb, 20 ) assert_equal( inst.cell_index, c1.cell_index ) - if( RBA::Application::instance.is_editable? ) - c2.each_inst { |inst| c2.erase( inst ) } - assert_equal( c2.bbox.to_s, "()" ) - else - c2.clear_insts - end + c2.each_inst { |inst| c2.erase( inst ) } assert_equal( c2.bbox.to_s, "()" ) tr = RBA::CplxTrans::new( 1.5, 90.0, true, RBA::DPoint::new( 100, -50 ) ) @@ -702,90 +693,86 @@ class DBLayoutTest_TestClass < TestBase # Instances and bboxes (editable mode) def test_6_Layout_new - if( RBA::Application::instance.is_editable? ) + ly = RBA::Layout::new + pid1 = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a ) + pid2 = ly.properties_id( { 100 => "x" }.to_a ) - ly = RBA::Layout::new - pid1 = ly.properties_id( { 17 => "a", "b" => [ 1, 5, 7 ] }.to_a ) - pid2 = ly.properties_id( { 100 => "x" }.to_a ) + ci1 = ly.add_cell( "c1" ) + ci2 = ly.add_cell( "c2" ) + ci3 = ly.add_cell( "c3" ) + c1 = ly.cell( ci1 ) + c2 = ly.cell( ci2 ) + c3 = ly.cell( ci3 ) - ci1 = ly.add_cell( "c1" ) - ci2 = ly.add_cell( "c2" ) - ci3 = ly.add_cell( "c3" ) - c1 = ly.cell( ci1 ) - c2 = ly.cell( ci2 ) - c3 = ly.cell( ci3 ) + tr = RBA::Trans::new( RBA::Trans::R90, RBA::Point::new( 100, -50 ) ) + inst_1 = RBA::CellInstArray::new( c1.cell_index, tr ) + new_inst_1 = c2.insert( inst_1, pid1 ) + new_inst_2 = c2.insert( inst_1, pid2 ) + inst_2 = RBA::CellInstArray::new( c3.cell_index, tr*tr ) + new_inst_3 = c1.insert( inst_2 ) - tr = RBA::Trans::new( RBA::Trans::R90, RBA::Point::new( 100, -50 ) ) - inst_1 = RBA::CellInstArray::new( c1.cell_index, tr ) - new_inst_1 = c2.insert( inst_1, pid1 ) - new_inst_2 = c2.insert( inst_1, pid2 ) - inst_2 = RBA::CellInstArray::new( c3.cell_index, tr*tr ) - new_inst_3 = c1.insert( inst_2 ) + assert_equal( new_inst_1.cell_index, c1.cell_index ) + assert_equal( new_inst_1.trans.to_s, tr.to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, 0 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - assert_equal( new_inst_1.cell_index, c1.cell_index ) - assert_equal( new_inst_1.trans.to_s, tr.to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, 0 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - new_inst_3 = c1.replace_prop_id( new_inst_3, pid2 ) - - assert_equal( new_inst_1.cell_index, c1.cell_index ) - assert_equal( new_inst_1.trans.to_s, tr.to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, pid2 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - begin - new_inst_1 = c1.replace( new_inst_1, inst_2 ) - assert_equal( true, false ) - rescue - # OK: gives an error since we are trying to erase an object from a list that is does not belong to - end - - new_inst_1 = c2.replace( new_inst_1, inst_2 ) - - assert_equal( new_inst_1.cell_index, c3.cell_index ) - assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, pid2 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - new_inst_1 = c2.replace( new_inst_1, inst_2, pid1 ) - - assert_equal( new_inst_1.cell_index, c3.cell_index ) - assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) - assert_equal( new_inst_1.prop_id, pid1 ) - assert_equal( new_inst_2.cell_index, c1.cell_index ) - assert_equal( new_inst_2.trans.to_s, tr.to_s ) - assert_equal( new_inst_2.prop_id, pid2 ) - assert_equal( new_inst_3.cell_index, c3.cell_index ) - assert_equal( new_inst_3.prop_id, pid2 ) - assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) - - assert_equal( new_inst_1.is_null?, false ) - assert_equal( RBA::Instance.new.is_null?, true ) - - assert_equal( c2.is_leaf?, false ) - c2.erase( new_inst_1 ) - c2.erase( new_inst_2 ) - assert_equal( c2.is_leaf?, true ) - assert_equal( c2.child_instances, 0 ) + new_inst_3 = c1.replace_prop_id( new_inst_3, pid2 ) + + assert_equal( new_inst_1.cell_index, c1.cell_index ) + assert_equal( new_inst_1.trans.to_s, tr.to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, pid2 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) + begin + new_inst_1 = c1.replace( new_inst_1, inst_2 ) + assert_equal( true, false ) + rescue + # OK: gives an error since we are trying to erase an object from a list that is does not belong to end + new_inst_1 = c2.replace( new_inst_1, inst_2 ) + + assert_equal( new_inst_1.cell_index, c3.cell_index ) + assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, pid2 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) + + new_inst_1 = c2.replace( new_inst_1, inst_2, pid1 ) + + assert_equal( new_inst_1.cell_index, c3.cell_index ) + assert_equal( new_inst_1.trans.to_s, (tr*tr).to_s ) + assert_equal( new_inst_1.prop_id, pid1 ) + assert_equal( new_inst_2.cell_index, c1.cell_index ) + assert_equal( new_inst_2.trans.to_s, tr.to_s ) + assert_equal( new_inst_2.prop_id, pid2 ) + assert_equal( new_inst_3.cell_index, c3.cell_index ) + assert_equal( new_inst_3.prop_id, pid2 ) + assert_equal( new_inst_3.trans.to_s, (tr*tr).to_s ) + + assert_equal( new_inst_1.is_null?, false ) + assert_equal( RBA::Instance.new.is_null?, true ) + + assert_equal( c2.is_leaf?, false ) + c2.erase( new_inst_1 ) + c2.erase( new_inst_2 ) + assert_equal( c2.is_leaf?, true ) + assert_equal( c2.child_instances, 0 ) + end def shapes_to_s(ly, shapes) @@ -810,11 +797,6 @@ class DBLayoutTest_TestClass < TestBase # Copy/move between cells def test_7_cells_copy_move - # because of set_property ... - if !RBA::Application::instance.is_editable? - return - end - ly1 = RBA::Layout::new la1 = ly1.insert_layer(RBA::LayerInfo::new(1, 0)) lb1 = ly1.insert_layer(RBA::LayerInfo::new(2, 0)) @@ -976,54 +958,50 @@ class DBLayoutTest_TestClass < TestBase c3.each_inst { |i| str << i.to_s(true) } assert_equal(str.join(";"), "") - if RBA::Application::instance.is_editable? + i1.cell_index = ci3 - i1.cell_index = ci3 + str = [] + c1.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "c3 r90 100,-50") - str = [] - c1.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "c3 r90 100,-50") + str = [] + c2.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c2.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + str = [] + c3.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c3.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + i1.cell = c2 - i1.cell = c2 + str = [] + c1.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "c2 r90 100,-50") - str = [] - c1.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "c2 r90 100,-50") + str = [] + c2.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c2.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + str = [] + c3.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c3.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + assert_equal(i1.parent_cell.name, "c1") - assert_equal(i1.parent_cell.name, "c1") + i1.cell = c1 + i1.parent_cell = c2 - i1.cell = c1 - i1.parent_cell = c2 + str = [] + c1.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") - str = [] - c1.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") + str = [] + c2.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "c1 r90 100,-50") - str = [] - c2.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "c1 r90 100,-50") - - str = [] - c3.each_inst { |i| str << i.to_s(true) } - assert_equal(str.join(";"), "") - - end + str = [] + c3.each_inst { |i| str << i.to_s(true) } + assert_equal(str.join(";"), "") end diff --git a/testdata/ruby/layMenuTest.rb b/testdata/ruby/layMenuTest.rb index 891070c59..a0135a7bf 100644 --- a/testdata/ruby/layMenuTest.rb +++ b/testdata/ruby/layMenuTest.rb @@ -313,6 +313,10 @@ RESULT def test_3 + if !RBA.constants.member?(:AbstractMenu) + return + end + map = RBA::AbstractMenu::unpack_key_binding("'path.a':X;'path.b':''") assert_equal(map["path.a"], "X") assert_equal(map["path.b"], "") @@ -333,6 +337,10 @@ RESULT def test_4 + if !RBA.constants.member?(:Action) + return + end + action = RBA::Action::new action.title = "title:n1" @@ -359,6 +367,10 @@ RESULT def test_5 + if !RBA.constants.member?(:Action) + return + end + action = RBA::Action::new action.title = "title:n1" @@ -386,6 +398,10 @@ RESULT def test_6 + if !RBA.constants.member?(:Application) + return + end + app = RBA::Application.instance mw = app.main_window