1 // =================================
  2 // Copyright (c) 2022 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Os;
  8 using System.Message;
  9 
 10 namespace System.Screen
 11 {
 12     string MakeApplicationMessageQueueName()
 13     {
 14         return "system.screen.msg.queue." + ToString(GetPid());
 15     }
 16 
 17     public class Application
 18     {
 19         static Application() : instance(new Application())
 20         {
 21         }
 22         public ~Application()
 23         {
 24             try
 25             {
 26                 UnbindTerminal();
 27                 CloseMsgQ(msgQ);
 28             }
 29             catch (const Exception& ex)
 30             {
 31             }
 32         }
 33         public static Application& Instance()
 34         {
 35             return *instance;
 36         }
 37         private Application() : msgQ(MsgQ(MakeApplicationMessageQueueName().Chars()))menuBar(null)focusedControl(null)lastDefaultWriteScreenMessageWindow(-1)
 38         {
 39             RegisterMessage<KeyPressedMessage>(systemScreenKeyPressedMessageId);
 40             BindTerminal(msgQ);
 41         }
 42         public nothrow Window* MainWindow()
 43         {
 44             return mainWindow;
 45         }
 46         public nothrow MenuBar* GetMenuBar() const
 47         {
 48             return menuBar;
 49         }
 50         public nothrow void SetMenuBar(MenuBar* menuBar_)
 51         {
 52             menuBar = menuBar_;
 53             menuBarWindowHandle = menuBar->Handle();
 54         }
 55         public nothrow void SetStatusBar(StatusBar* statusBar_)
 56         {
 57             statusBar = statusBar_;
 58             statusBarWindowHandle = statusBar->Handle();
 59         }
 60         public WindowManager& GetWindowManager() const
 61         {
 62             return windowManager;
 63         }
 64         public void Run(Window& mainWindow_)
 65         {
 66             mainWindow = &mainWindow_;
 67             mainWindow->SetMainWindow();
 68             mainWindow->SetLocation(Point(00));
 69             mainWindow->SetSize(Size(TerminalWindowWidth()TerminalWindowHeight()));
 70             mainWindow->Invalidate();
 71             UniquePtr<Message> message = ReadMessage();
 72             while (!(message.Get() is QuitMessage*))
 73             {
 74                 bool handled = false;
 75                 if (message->TargetWindowHandle() != -1)
 76                 {
 77                     Control* control = windowManager.GetWindow(message->TargetWindowHandle());
 78                     if (control != null)
 79                     {
 80                         handled = control->HandleMessage(message.Get());
 81                     }
 82                 }
 83                 if (!handled)
 84                 {
 85                     handled = mainWindow->HandleMessage(message.Get());
 86                 }
 87                 message = ReadMessage();
 88             }
 89             Terminal.Out() << ResetColors();
 90             ClearScreen(TerminalWindowWidth()TerminalWindowHeight());
 91             SetCursorPos(00);
 92         }
 93         public void RunDialog(Window* window)
 94         {
 95             WriteScreenMessage writeScreenMessage(Rect.Default()InvalidateKind.invalidateIfNotDefault);
 96             mainWindow->HandleWriteScreen(&writeScreenMessage);
 97             UniquePtr<Message> message = ReadMessage();
 98             while (!(message.Get() is QuitMessage*))
 99             {
100                 bool handled = window->HandleMessage(message.Get());
101                 if (handled)
102                 {
103                     if (window->GetDialogResult() != DialogResult.none)
104                     {
105                         WriteScreenMessage writeScreenMessage(window->GetRect()InvalidateKind.invalidateIfNotDefault);
106                         mainWindow->HandleWriteScreen(&writeScreenMessage);
107                         return;
108                     }
109                 }
110                 message = ReadMessage();
111             }
112         }
113         public void Exit()
114         {
115             QuitMessage quitMessage;
116             PostMessage(quitMessage);
117         }
118         public void PostMessage(Message& message)
119         {
120             if (message.TargetWindowHandle() != menuBarWindowHandle && message.TargetWindowHandle() != statusBarWindowHandle)
121             {
122                 if (message.IsDefaultWriteScreenMessage())
123                 {
124                     if (lastDefaultWriteScreenMessageWindow == message.TargetWindowHandle())
125                     {
126                         return;
127                     }
128                     else
129                     {
130                         lastDefaultWriteScreenMessageWindow = message.TargetWindowHandle();
131                     }
132                 }
133                 else
134                 {
135                     lastDefaultWriteScreenMessageWindow = -1;
136                 }
137             }
138             int msgSize = message.Size();
139             UniquePtr<byte> msg(cast<byte*>(MemAlloc(msgSize)));
140             MemoryWriter writer(msg.Get()msgSize);
141             message.Write(writer);
142             PutMsg(msgQmsg.Get()msgSize);
143         }
144         public UniquePtr<Message> ReadMessage()
145         {
146             WaitMsg(msgQ);
147             return GetMessage();
148         }
149         public void Timer(const Duration& durationControl* controlint timerId)
150         {
151             TimerMessage message(timerId);
152             message.SetTargetWindowHandle(control->Handle());
153             int msgSize = message.Size();
154             UniquePtr<byte> msg(cast<byte*>(MemAlloc(msgSize)));
155             MemoryWriter writer(msg.Get()msgSize);
156             message.Write(writer);
157             TimerMsg(durationmsgQmsg.Get()msgSize);
158         }
159         public nothrow Control* FocusedControl() const
160         {
161             return focusedControl;
162         }
163         public nothrow void SetFocusedControl(Control* focusedControl_)
164         {
165             focusedControl = focusedControl_;
166         }
167         private UniquePtr<Message> GetMessage()
168         {
169             int qlen = GetMsgQLength(msgQ);
170             if (qlen > 0)
171             {
172                 int msgSize = GetMsgSize(msgQ);
173                 if (msgSize > 0)
174                 {
175                     UniquePtr<byte> msgData(cast<byte*>(MemAlloc(msgSize)));
176                     GetMsg(msgQmsgData.Get());
177                     UniquePtr<Message> message(ReadMessage(msgData.Get()msgSize));
178                     return message;
179                 }
180                 else
181                 {
182                     throw Exception("invalid message size 0");
183                 }
184             }
185             else
186             {
187                 throw Exception("message queue " + ToString(msgQ) + " is empty");
188             }
189         }
190         private static UniquePtr<Application> instance;
191         private int msgQ;
192         private Window* mainWindow;
193         private WindowManager windowManager;
194         private MenuBar* menuBar;
195         private StatusBar* statusBar;
196         private Control* focusedControl;
197         private int lastDefaultWriteScreenMessageWindow;
198         private int menuBarWindowHandle;
199         private int statusBarWindowHandle;
200     }
201 }