comparison dwtestoo.cpp @ 2933:3cdb02171b01

C++: Implement Thread class and add the last page Thread/Event.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Sat, 31 Dec 2022 00:41:28 +0000
parents 3f660f47a45f
children 6d3da42f63af
comparison
equal deleted inserted replaced
2932:3f660f47a45f 2933:3cdb02171b01
30 30
31 #define APP_TITLE "Dynamic Windows C++" 31 #define APP_TITLE "Dynamic Windows C++"
32 #define APP_EXIT "Are you sure you want to exit?" 32 #define APP_EXIT "Are you sure you want to exit?"
33 33
34 #define MAX_WIDGETS 20 34 #define MAX_WIDGETS 20
35 #define BUF_SIZE 1024
35 36
36 // Handle the case of very old compilers by using 37 // Handle the case of very old compilers by using
37 // A simple non-lambda example instead. 38 // A simple non-lambda example instead.
38 #ifndef DW_LAMBDA 39 #ifndef DW_LAMBDA
39 40
464 if(fontname) 465 if(fontname)
465 snprintf(font, 100, "%d.%s", fontsize, fontname); 466 snprintf(font, 100, "%d.%s", fontsize, fontname);
466 mle->SetFont(fontname ? font : NULL); 467 mle->SetFont(fontname ? font : NULL);
467 } 468 }
468 469
470 // Thread and Event functions
471 void UpdateMLE(DW::MLE *threadmle, char *text, DW::Mutex *mutex)
472 {
473 static unsigned int pos = 0;
474
475 // Protect pos from being changed by different threads
476 if(mutex)
477 mutex->Lock();
478 pos = threadmle->Import(text, pos);
479 threadmle->SetCursor(pos);
480 if(mutex)
481 mutex->Unlock();
482 }
483
484 void RunThread(int threadnum, DW::Mutex *mutex, DW::Event *controlevent, DW::Event *workevent, DW::MLE *threadmle) {
485 char buf[BUF_SIZE+1] = {0};
486
487 snprintf(buf, BUF_SIZE, "Thread %d started.\r\n", threadnum);
488 UpdateMLE(threadmle, buf, mutex);
489
490 // Increment the ready count while protected by mutex
491 dw_mutex_lock(mutex);
492 ready++;
493 // If all 4 threads have incrememted the ready count...
494 // Post the control event semaphore so things will get started.
495 if(ready == 4)
496 controlevent->Post();
497 mutex->Unlock();
498
499 while(!finished)
500 {
501 int result = workevent->Wait(2000);
502
503 if(result == DW_ERROR_TIMEOUT)
504 {
505 snprintf(buf, BUF_SIZE, "Thread %d timeout waiting for event.\r\n", threadnum);
506 UpdateMLE(threadmle, buf, mutex);
507 }
508 else if(result == DW_ERROR_NONE)
509 {
510 snprintf(buf, BUF_SIZE, "Thread %d doing some work.\r\n", threadnum);
511 UpdateMLE(threadmle, buf, mutex);
512 // Pretend to do some work
513 app->MainSleep(1000 * threadnum);
514
515 // Increment the ready count while protected by mutex
516 mutex->Lock();
517 ready++;
518 sprintf(buf, "Thread %d work done. ready=%d", threadnum, ready);
519 // If all 4 threads have incrememted the ready count...
520 // Post the control event semaphore so things will get started.
521 if(ready == 4)
522 {
523 controlevent->Post();
524 strcat(buf, " Control posted.");
525 }
526 mutex->Unlock();
527 strcat(buf, "\r\n");
528 UpdateMLE(threadmle, buf, mutex);
529 }
530 else
531 {
532 snprintf(buf, BUF_SIZE, "Thread %d error %d.\r\n", threadnum, result);
533 UpdateMLE(threadmle, buf, mutex);
534 app->MainSleep(10000);
535 }
536 }
537 snprintf(buf, BUF_SIZE, "Thread %d finished.\r\n", threadnum);
538 UpdateMLE(threadmle, buf, mutex);
539 }
540
541 void ControlThread(DW::Mutex *mutex, DW::Event *controlevent, DW::Event *workevent, DW::MLE *threadmle) {
542 int inprogress = 5;
543 char buf[BUF_SIZE+1] = {0};
544
545 while(inprogress)
546 {
547 int result = controlevent->Wait(2000);
548
549 if(result == DW_ERROR_TIMEOUT)
550 {
551 UpdateMLE(threadmle, "Control thread timeout waiting for event.\r\n", mutex);
552 }
553 else if(result == DW_ERROR_NONE)
554 {
555 // Reset the control event
556 controlevent->Reset();
557 ready = 0;
558 snprintf(buf, BUF_SIZE, "Control thread starting worker threads. Inprogress=%d\r\n", inprogress);
559 UpdateMLE(threadmle, buf, mutex);
560 // Start the work threads
561 workevent->Post();
562 app->MainSleep(100);
563 // Reset the work event
564 workevent->Reset();
565 inprogress--;
566 }
567 else
568 {
569 snprintf(buf, BUF_SIZE, "Control thread error %d.\r\n", result);
570 UpdateMLE(threadmle, buf, mutex);
571 app->MainSleep(10000);
572 }
573 }
574 // Tell the other threads we are done
575 finished = TRUE;
576 workevent->Post();
577 // Close the control event
578 controlevent->Close();
579 UpdateMLE(threadmle, "Control thread finished.\r\n", mutex);
580 }
581
469 // Add the menus to the window 582 // Add the menus to the window
470 void CreateMenus() { 583 void CreateMenus() {
471 // Setup the menu 584 // Setup the menu
472 DW::MenuBar *menubar = this->MenuBarNew(); 585 DW::MenuBar *menubar = this->MenuBarNew();
473 586
539 { 652 {
540 DW::Box *lbbox = new DW::Box(DW_VERT, 10); 653 DW::Box *lbbox = new DW::Box(DW_VERT, 10);
541 654
542 notebookbox->PackStart(lbbox, 150, 70, TRUE, TRUE, 0); 655 notebookbox->PackStart(lbbox, 150, 70, TRUE, TRUE, 0);
543 656
544 /* Copy and Paste */ 657 // Copy and Paste
545 DW::Box *browsebox = new DW::Box(DW_HORZ, 0); 658 DW::Box *browsebox = new DW::Box(DW_HORZ, 0);
546 lbbox->PackStart(browsebox, 0, 0, FALSE, FALSE, 0); 659 lbbox->PackStart(browsebox, 0, 0, FALSE, FALSE, 0);
547 660
548 DW::Entryfield *copypastefield = new DW::Entryfield(); 661 DW::Entryfield *copypastefield = new DW::Entryfield();
549 copypastefield->SetLimit(260); 662 copypastefield->SetLimit(260);
553 browsebox->PackStart(copybutton, FALSE, FALSE, 0); 666 browsebox->PackStart(copybutton, FALSE, FALSE, 0);
554 667
555 DW::Button *pastebutton = new DW::Button("Paste"); 668 DW::Button *pastebutton = new DW::Button("Paste");
556 browsebox->PackStart(pastebutton, FALSE, FALSE, 0); 669 browsebox->PackStart(pastebutton, FALSE, FALSE, 0);
557 670
558 /* Archive Name */ 671 // Archive Name
559 DW::Text *stext = new DW::Text("File to browse"); 672 DW::Text *stext = new DW::Text("File to browse");
560 stext->SetStyle(DW_DT_VCENTER); 673 stext->SetStyle(DW_DT_VCENTER);
561 lbbox->PackStart(stext, 130, 15, TRUE, TRUE, 2); 674 lbbox->PackStart(stext, 130, 15, TRUE, TRUE, 2);
562 675
563 browsebox = new DW::Box(DW_HORZ, 0); 676 browsebox = new DW::Box(DW_HORZ, 0);
594 //this->ClickDefault(cancelbutton); 707 //this->ClickDefault(cancelbutton);
595 708
596 DW::Button *colorchoosebutton = new DW::Button("Color Chooser Dialog"); 709 DW::Button *colorchoosebutton = new DW::Button("Color Chooser Dialog");
597 buttonbox->PackStart(colorchoosebutton, 130, 30, TRUE, TRUE, 2); 710 buttonbox->PackStart(colorchoosebutton, 130, 30, TRUE, TRUE, 2);
598 711
599 /* Set some nice fonts and colors */ 712 // Set some nice fonts and colors
600 lbbox->SetColor(DW_CLR_DARKCYAN, DW_CLR_PALEGRAY); 713 lbbox->SetColor(DW_CLR_DARKCYAN, DW_CLR_PALEGRAY);
601 buttonbox->SetColor(DW_CLR_DARKCYAN, DW_CLR_PALEGRAY); 714 buttonbox->SetColor(DW_CLR_DARKCYAN, DW_CLR_PALEGRAY);
602 okbutton->SetColor(DW_CLR_PALEGRAY, DW_CLR_DARKCYAN); 715 okbutton->SetColor(DW_CLR_PALEGRAY, DW_CLR_DARKCYAN);
603 #ifdef COLOR_DEBUG 716 #ifdef COLOR_DEBUG
604 copypastefield->SetColor(DW_CLR_WHITE, DW_CLR_RED); 717 copypastefield->SetColor(DW_CLR_WHITE, DW_CLR_RED);
990 { 1103 {
991 this->DrawShapes(FALSE, pixmap); 1104 this->DrawShapes(FALSE, pixmap);
992 } 1105 }
993 else if(page_num == 1) 1106 else if(page_num == 1)
994 { 1107 {
995 /* Get the font size for this printer context... */ 1108 // Get the font size for this printer context...
996 int fheight, fwidth; 1109 int fheight, fwidth;
997 1110
998 /* If we have a file to display... */ 1111 // If we have a file to display...
999 if(current_file) 1112 if(current_file)
1000 { 1113 {
1001 int nrows; 1114 int nrows;
1002 1115
1003 /* Calculate new dimensions */ 1116 // Calculate new dimensions
1004 pixmap->GetTextExtents("(g", NULL, &fheight); 1117 pixmap->GetTextExtents("(g", NULL, &fheight);
1005 nrows = (int)(pixmap->GetHeight() / fheight); 1118 nrows = (int)(pixmap->GetHeight() / fheight);
1006 1119
1007 /* Do the actual drawing */ 1120 // Do the actual drawing
1008 this->DrawFile(0, 0, nrows, fheight, pixmap); 1121 this->DrawFile(0, 0, nrows, fheight, pixmap);
1009 } 1122 }
1010 else 1123 else
1011 { 1124 {
1012 /* We don't have a file so center an error message on the page */ 1125 // We don't have a file so center an error message on the page
1013 const char *text = "No file currently selected!"; 1126 const char *text = "No file currently selected!";
1014 int posx, posy; 1127 int posx, posy;
1015 1128
1016 pixmap->GetTextExtents(text, &fwidth, &fheight); 1129 pixmap->GetTextExtents(text, &fwidth, &fheight);
1017 1130
1072 DW::Tree *tree = new DW::Tree(); 1185 DW::Tree *tree = new DW::Tree();
1073 if(tree->GetHWND()) 1186 if(tree->GetHWND())
1074 { 1187 {
1075 notebookbox->PackStart(tree, 500, 200, TRUE, TRUE, 1); 1188 notebookbox->PackStart(tree, 500, 200, TRUE, TRUE, 1);
1076 1189
1077 /* and a status area to see whats going on */ 1190 // and a status area to see whats going on
1078 DW::StatusText *tree_status = new DW::StatusText(); 1191 DW::StatusText *tree_status = new DW::StatusText();
1079 notebookbox->PackStart(tree_status, 100, DW_SIZE_AUTO, TRUE, FALSE, 1); 1192 notebookbox->PackStart(tree_status, 100, DW_SIZE_AUTO, TRUE, FALSE, 1);
1080 1193
1081 // set up our signal trappers... 1194 // set up our signal trappers...
1082 tree->ConnectItemContext([this, tree_status](char *text, int x, int y, void *data) -> int 1195 tree->ConnectItemContext([this, tree_status](char *text, int x, int y, void *data) -> int
1488 } 1601 }
1489 free(text); 1602 free(text);
1490 // now insert a couple of items 1603 // now insert a couple of items
1491 combobox2->Insert("inserted item 2", 2); 1604 combobox2->Insert("inserted item 2", 2);
1492 combobox2->Insert("inserted item 5", 5); 1605 combobox2->Insert("inserted item 5", 5);
1493 /* make a spinbutton */ 1606 // make a spinbutton
1494 DW::SpinButton *spinbutton = new DW::SpinButton(); 1607 DW::SpinButton *spinbutton = new DW::SpinButton();
1495 combox->PackStart(spinbutton, TRUE, FALSE, 0); 1608 combox->PackStart(spinbutton, TRUE, FALSE, 0);
1496 spinbutton->SetLimits(100, 1); 1609 spinbutton->SetLimits(100, 1);
1497 spinbutton->SetPos(30); 1610 spinbutton->SetPos(30);
1498 1611
1499 spinbutton->ConnectValueChanged([this](int value) -> int 1612 spinbutton->ConnectValueChanged([this](int value) -> int
1500 { 1613 {
1501 this->app->MessageBox("DWTest", DW_MB_OK, "New value from spinbutton: %d\n", value); 1614 this->app->MessageBox("DWTest", DW_MB_OK, "New value from spinbutton: %d\n", value);
1502 return TRUE; 1615 return TRUE;
1503 }); 1616 });
1504 /// make a slider 1617 // make a slider
1505 DW::Slider *slider = new DW::Slider(FALSE, 11, 0); 1618 DW::Slider *slider = new DW::Slider(FALSE, 11, 0);
1506 combox->PackStart(slider, TRUE, FALSE, 0); 1619 combox->PackStart(slider, TRUE, FALSE, 0);
1507 1620
1508 // make a percent 1621 // make a percent
1509 DW::Percent *percent = new DW::Percent(); 1622 DW::Percent *percent = new DW::Percent();
1646 // Page 7 - ScrollBox 1759 // Page 7 - ScrollBox
1647 void CreateScrollBox(DW::Box *notebookbox) 1760 void CreateScrollBox(DW::Box *notebookbox)
1648 { 1761 {
1649 char buf[101] = {0}; 1762 char buf[101] = {0};
1650 1763
1651 /* create a box to pack into the notebook page */ 1764 // create a box to pack into the notebook page
1652 DW::ScrollBox *scrollbox = new DW::ScrollBox(DW_VERT, 0); 1765 DW::ScrollBox *scrollbox = new DW::ScrollBox(DW_VERT, 0);
1653 notebookbox->PackStart(scrollbox, 0, 0, TRUE, TRUE, 1); 1766 notebookbox->PackStart(scrollbox, 0, 0, TRUE, TRUE, 1);
1654 1767
1655 DW::Button *adjbutton = new DW::Button("Show Adjustments", 0); 1768 DW::Button *adjbutton = new DW::Button("Show Adjustments", 0);
1656 scrollbox->PackStart(adjbutton, FALSE, FALSE, 0); 1769 scrollbox->PackStart(adjbutton, FALSE, FALSE, 0);
1672 snprintf(buf, 100, "Entry %d", i); 1785 snprintf(buf, 100, "Entry %d", i);
1673 DW::Entryfield *entry = new DW::Entryfield(buf , i); 1786 DW::Entryfield *entry = new DW::Entryfield(buf , i);
1674 tmpbox->PackStart(entry, 0, DW_SIZE_AUTO, TRUE, FALSE, 0); 1787 tmpbox->PackStart(entry, 0, DW_SIZE_AUTO, TRUE, FALSE, 0);
1675 } 1788 }
1676 } 1789 }
1790
1791 // Page 8 - Thread and Event
1792 void CreateThreadEvent(DW::Box *notebookbox)
1793 {
1794 // create a box to pack into the notebook page
1795 DW::Box *tmpbox = new DW::Box(DW_VERT, 0);
1796 notebookbox->PackStart(tmpbox, 0, 0, TRUE, TRUE, 1);
1797
1798 DW::Button *startbutton = new DW::Button("Start Threads");
1799 tmpbox->PackStart(startbutton, FALSE, FALSE, 0);
1800
1801 // Create the base threading components
1802 DW::MLE *threadmle = new DW::MLE();
1803 tmpbox->PackStart(threadmle, 1, 1, TRUE, TRUE, 0);
1804 DW::Mutex *mutex = new DW::Mutex();
1805 DW::Event *workevent = new DW::Event();
1806
1807 startbutton->ConnectClicked([this, mutex, workevent, threadmle, startbutton]() -> int
1808 {
1809 startbutton->Disable();
1810 mutex->Lock();
1811 DW::Event *controlevent = new DW::Event();
1812 workevent->Reset();
1813 finished = FALSE;
1814 ready = 0;
1815 UpdateMLE(threadmle, "Starting thread 1\r\n", DW_NULL);
1816 new DW::Thread([this, startbutton, mutex, controlevent, workevent, threadmle](DW::Thread *thread) -> void {
1817 this->RunThread(1, mutex, controlevent, workevent, threadmle);
1818 });
1819 UpdateMLE(threadmle, "Starting thread 2\r\n", DW_NULL);
1820 new DW::Thread([this, startbutton, mutex, controlevent, workevent, threadmle](DW::Thread *thread) -> void {
1821 this->RunThread(2, mutex, controlevent, workevent, threadmle);
1822 });
1823 UpdateMLE(threadmle, "Starting thread 3\r\n", DW_NULL);
1824 new DW::Thread([this, startbutton, mutex, controlevent, workevent, threadmle](DW::Thread *thread) -> void {
1825 this->RunThread(3, mutex, controlevent, workevent, threadmle);
1826 });
1827 UpdateMLE(threadmle, "Starting thread 4\r\n", DW_NULL);
1828 new DW::Thread([this, startbutton, mutex, controlevent, workevent, threadmle](DW::Thread *thread) -> void {
1829 this->RunThread(4, mutex, controlevent, workevent, threadmle);
1830 });
1831 UpdateMLE(threadmle, "Starting control thread\r\n", DW_NULL);
1832 new DW::Thread([this, startbutton, mutex, controlevent, workevent, threadmle](DW::Thread *thread) -> void {
1833 this->ControlThread(mutex, controlevent, workevent, threadmle);
1834 startbutton->Enable();
1835 });
1836 mutex->Unlock();
1837 return FALSE;
1838 });
1839 }
1677 public: 1840 public:
1678 // Constructor creates the application 1841 // Constructor creates the application
1679 DWTest(const char *title): DW::Window(title) { 1842 DWTest(const char *title): DW::Window(title) {
1680 // Get our application singleton 1843 // Get our application singleton
1681 app = DW::App::Init(); 1844 app = DW::App::Init();
1690 /* First try the current directory */ 1853 /* First try the current directory */
1691 foldericon = app->LoadIcon(foldericonpath); 1854 foldericon = app->LoadIcon(foldericonpath);
1692 fileicon = app->LoadIcon(fileiconpath); 1855 fileicon = app->LoadIcon(fileiconpath);
1693 1856
1694 #ifdef PLATFORMFOLDER 1857 #ifdef PLATFORMFOLDER
1695 /* In case we are running from the build directory... 1858 // In case we are running from the build directory...
1696 * also check the appropriate platform subfolder 1859 // also check the appropriate platform subfolder
1697 */
1698 if(!foldericon) 1860 if(!foldericon)
1699 { 1861 {
1700 strncpy(foldericonpath, PLATFORMFOLDER "folder", 1024); 1862 strncpy(foldericonpath, PLATFORMFOLDER "folder", 1024);
1701 foldericon = app->LoadIcon(foldericonpath); 1863 foldericon = app->LoadIcon(foldericonpath);
1702 } 1864 }
1705 strncpy(fileiconpath, PLATFORMFOLDER "file", 1024); 1867 strncpy(fileiconpath, PLATFORMFOLDER "file", 1024);
1706 fileicon = app->LoadIcon(fileiconpath); 1868 fileicon = app->LoadIcon(fileiconpath);
1707 } 1869 }
1708 #endif 1870 #endif
1709 1871
1710 /* Finally try from the platform application directory */ 1872 // Finally try from the platform application directory
1711 if(!foldericon && !fileicon) 1873 if(!foldericon && !fileicon)
1712 { 1874 {
1713 char *appdir = app->GetDir(); 1875 char *appdir = app->GetDir();
1714 char pathbuff[1025] = {0}; 1876 char pathbuff[1025] = {0};
1715 int pos = (int)strlen(appdir); 1877 int pos = (int)strlen(appdir);
1782 CreateScrollBox(notebookbox); 1944 CreateScrollBox(notebookbox);
1783 notebookpage = notebook->PageNew(); 1945 notebookpage = notebook->PageNew();
1784 notebook->Pack(notebookpage, notebookbox); 1946 notebook->Pack(notebookpage, notebookbox);
1785 notebook->PageSetText(notebookpage, "scrollbox"); 1947 notebook->PageSetText(notebookpage, "scrollbox");
1786 1948
1949 // Create Notebook Page 8 - Thread and Event
1950 notebookbox = new DW::Box(DW_VERT, 5);
1951 CreateThreadEvent(notebookbox);
1952 notebookpage = notebook->PageNew();
1953 notebook->Pack(notebookpage, notebookbox);
1954 notebook->PageSetText(notebookpage, "thread/event");
1955
1787 // Finalize the window 1956 // Finalize the window
1788 this->SetSize(640, 550); 1957 this->SetSize(640, 550);
1789 1958
1790 timer = new DW::Timer(2000, [this]() -> int 1959 timer = new DW::Timer(2000, [this]() -> int
1791 { 1960 {
1819 char **lp; 1988 char **lp;
1820 char *current_file = NULL; 1989 char *current_file = NULL;
1821 1990
1822 // Page 4 1991 // Page 4
1823 int mle_point=-1; 1992 int mle_point=-1;
1993
1994 // Page 8
1995 int finished = FALSE, ready = 0;
1824 1996
1825 // Miscellaneous 1997 // Miscellaneous
1826 int menu_enabled = TRUE; 1998 int menu_enabled = TRUE;
1827 HICN fileicon, foldericon; 1999 HICN fileicon, foldericon;
1828 char fileiconpath[1025] = "file"; 2000 char fileiconpath[1025] = "file";