MiniGUI architecture 2 multi-window management and controls

Source: Internet
Author: User
Tags old windows

This is the second article in the MiniGUI architecture series, focusing on the Multi-Window Mechanism of MiniGUI and related window technologies. It involves window Z sequence, window cut, control class and control, and input method module design.
1 Introduction

In any complicated GUI system, processing window intercutting is the primary solution. Because the multi-window system must first ensure that the Drawing Output in one window does not affect the other window. Therefore, the GUI system generally uses the Z sequence to manage the inter-window shear relationships. Based on the position of the window in the Z sequence, the GUI system calculates the cut area of each window, that is, the cut field. Generally, the cut field of a window is defined as a set of rectangles that do not overlap with each other. The underlying graphics engine of the GUI system performs the output cutting operation based on the current output shear field when outputting data in the Inbound direction. This ensures that the Drawing Output of the window does not affect each other. Because the creation, destruction, hiding, and display of any window may affect the cut fields of other windows, an efficient cut domain Maintenance Algorithm is required first. This article describes the algorithm for generating cut fields in MiniGUI in detail.

Many people are quite familiar with the concept of controls (or components. Controls can be understood as subwindows in the main window. These subwindows act the same way as the main window, that is, they can receive external inputs, such as the keyboard and mouse, you can also make the output in your own region-but all their activities are restricted in the main window. MiniGUI also supports subwindows and can be nested in subwindows to create subwindows. All subwindows in MiniGUI are called controls.

In Windows or X Window, some control classes are pre-defined. After a control class is used to create a control, all controls belonging to the control class share the same behavior and display. Using these technologies, we can ensure consistent human-machine operation interfaces. For programmers, we can build graphical user interfaces like building blocks. MiniGUI uses the concepts of control classes and controls, and can easily overload existing controls, so that it has some special effects. For example, to create an edit box that only allows numbers to be entered, You can reload the existing edit box without re-writing a new control class.

In a multilingual environment, the input method is an essential module. The input method provides the ability to translate standard keyboard input into appropriate languages. MiniGUI also contains standard Chinese Simplified input methods, including full spelling, five strokes, and intelligent pinyin. This article will introduce the implementation of the input method module in MiniGUI.

2 window Z-order

The Z-order actually defines the cascade order between windows. The name "Z-order" is relative to the screen coordinate. Generally, all windows on the screen have a coordinate system, that is, the origin is in the upper left corner, the X axis is horizontal to the right, and the Y axis is vertical to the downward coordinate system. The Z-axis is relative to a hypothetical z-axis, which points out of the screen to the screen. The value of the window on the Z axis determines its Z order. A window with a large Z-order value overwrites a window with a small Z-order value.

Of course, in the program, the Z sequence is generally expressed as a linked list. The closer the node is to the head of the linked list, the greater its Z-order value. In MiniGUI, we maintain two z orders. One of them is always located on the other. In this way, you can create a window that is always located on top of other windows, such as an input window. If you specify the ws_ex_topmost extension attribute when creating a window, you can create such a main window. Because the operations in the Z-order are actually linked list operations, we will not go into detail here.

3 window Cut Algorithm

With the Z-order window, we can calculate the cut fields of each window. We call the cut domain generated by window Z sequence "global cut domain", which is relative to the cut domain defined by the window itself. We call the latter "local cut domain ". All outputs in the window are first affected by the global cut domain, and secondly by the local cut domain. Here we will focus on the generation and maintenance of global cut domains in the window.

3.1 generate and maintain global cut Domains

In MiniGUI, the cut field represents the union of several non-Intersecting rectangles, which are called cut rectangles. At first, when there is no window on the screen, the cut field of the desktop is composed of a rectangle, that is, a screen rectangle. When there is only one window on the screen, the cut field of the window is composed of a rectangle, this rectangle is the rectangle of the window on the screen, while the cut area of the desktop may be composed of multiple rectangles. Figure 1 illustrates the composition of the desktop cut domain when there is only one window. It can be seen that the cut field of the desktop is composed of four rectangles: A, B, C, and D. If the position of the window on the desktop changes to figure 2, the cut field of the desktop is composed of two rectangles (A and B ).


Figure 1 desktop shear domain composed of four rectangles


Figure 2 desktop shear domain composed of two rectangles

It is easy to see that, when there is only one window, there can be at most four rectangles that form the desktop cut domain.

In this case, if a new window appears, the new window will cut the old window and the desktop at the same time (Figure 3. The cut rectangle of the window is represented by a hollow rectangle, while the cut rectangle of the desktop is represented by a solid rectangle ). At this time, there will be more rectangles in the cut fields of the desktop and the old window. These rectangles should be the cut rectangles generated after each rectangle in the original cut field is affected by the new window rectangle. Similarly, each rectangle in the original cut field can only derive up to four new cut fields, and some rectangles are not affected by the new window rectangle.


Figure 3 cut fields of the desktop and old windows when a new window is created

In this way, we can generalize the global cut domain of a window into an exclude rectangle in the original cut domain:

  1. The global cut field of the window is initialized as the window rectangle.
  2. When another window overwrites the window, the global cut field of the window is the cut field after the new window rectangle is excluded.
  3. Iterate Step 1 in Z order until the top-level window is reached.

When a new window is displayed, MiniGUI processes the code of all other windows covered by the window. This Code calls the subtractcliprect function in the cut domain maintenance interface to calculate the new cut domain.

Listing 1 shows the global cut domain of the window overwritten by the new window when the new window is displayed // Clip all windows under this window. static void clip_windows_under_this (zorderinfo * zorder, pmainwin pwin, rect * rcwin) {pzordernode pnode; pgcrinfo; pnode = zorder-> ptopmost; while (pnode-> hwnd! = (Hwnd) pwin) pnode = pnode-> pnext; while (pnode) {If (pmainwin) (pnode-> hwnd )) -> dwstyle & ws_visible) {pgcrinfo = (pmainwin) (pnode-> hwnd)-> pgcrinfo; pthread_mutex_lock (& pgcrinfo-> lock ); subtractcliprect (& pgcrinfo-> crgn, rcwin); pgcrinfo-> Age ++; pthread_mutex_unlock (& pgcrinfo-> lock);} pnode = pnode-> pnext ;}}

The opposite operation to the exclude rectangle is to include a rectangle into the cut domain. This operation is used to hide or destroy a window. When a window is hidden or destroyed, all windows under the window will be affected. In this case, the rectangles of the hidden or destroyed window will be included in the global cut domain of these affected windows. Therefore, a function in the cut domain maintenance interface of MiniGUI is dedicated to this type of operation (includecliprect ). To ensure that the rectangles in the shear region do not overlap with each other, this function first calculates the intersecting rectangles of each shear rectangle, and then adds itself to the shear domain.

However, in some cases, we must recalculate the global cut fields of all windows, for example, when moving a window.

3.2 Cut the private heap of the rectangle

Obviously, when the cut domain is very complex or there are too many windows, a large number of rectangles are required to represent the global cut domain of each window. In C Programs, If you frequently use malloc and free to apply for and release each cut rectangle, there will be many problems. First, malloc and free are very time-consuming operations. Second, frequent malloc and free will lead to fragmentation of the C program heap, which may lead to future memory allocation failure. To avoid frequent use of malloc and free, MiniGUI creates a private heap during initialization. We can assign a cut rectangle directly from the heap without assigning a cut rectangle from the global heap of the process. This private heap is actually composed of some idle cut rectangles. The head node of the linked list is returned for each allocation, and the End Node of the linked list is placed at the release. If the linked list is empty, malloc is used to allocate a cut rectangle from the global heap of the process. Listing 2 illustrates the initialization and operation of the private heap.

Listing 2 allocate and release the cut rectangle pcliprect guiapi cliprectalloc (pfreecliprectlist plist) {pcliprect prect; # ifndef _ lite_version pthread_mutex_lock (& plist-> lock ); # endif if (plist-> head) {prect = plist-> head; plist-> head = prect-> next ;} else {If (plist-> free <plist-> size) {prect = plist-> heap + plist-> free; prect-> fromheap = true; plist-> free ++;} else {prect = malloc (sizeof (cliprect); If (prect = NULL) fprintf (stderr, "GDI error: alloc clip rect failure! \ N "); else prect-> fromheap = false; }}# ifndef _ lite_version pthread_mutex_unlock (& plist-> lock); # endif return prect ;} void guiapi freecliprect (pfreecliprectlist plist, cliprect * prect) {# ifndef _ lite_version pthread_mutex_lock (& plist-> lock); # endif prect-> next = NULL; if (plist-> head) {plist-> tail-> next = (pcliprect) prect; plist-> tail = (pcliprect) prect ;} else {plist-> head = plist-> tail = (pcliprect) prect;} # ifndef _ lite_version pthread_mutex_unlock (& plist-> lock); # endif}

4. Main Window and controls

4.1 controls and controls

If you have written a Windows application, you should understand the concept of window classes. In Windows, each window created by a program corresponds to a window class. This concept is similar to the relationship between classes and objects in object-oriented programming. By using object-oriented terminology, every window in Windows is actually an instance of a window class. Similar concepts exist in X Window Programming. For example, every widget we create is actually an instance of a widget class.

In this way, if the program needs to create a window, first make sure to select the correct window class, because each window class determines the appearance and behavior of the corresponding window instance. The appearance here refers to the appearance of the window, such as the Border width of the window, whether there is a title bar, and so on. Behavior refers to the window's response to user input. Every GUI system predefines some window classes, including buttons, list boxes, scroll bars, and edit boxes. If the window to be created by the program is special, you need to register a window class first, and then create an instance of this window class. This greatly improves the reusability of the Code.

In MiniGUI, we think the main window is usually a special window. Because the reusability of the Main Window code is generally very low, if you register a window class for each main window in the usual way, it will lead to additional unnecessary storage space, therefore, the window class is not supported in the main window. However, all the subwindows in the main window, that is, controls, support the concept of window classes (control classes. MiniGUI provides common predefined controls, including buttons (including single button and check button), static boxes, list boxes, progress bars, slide blocks, and edit boxes. The program can also customize its own control class, and then create the corresponding instance after registration. The code in listing 3 creates an edit box and a button.

Using the structure of control classes and control instances not only improves code reusability, but also facilitates the extension of existing control classes. For example, to create an edit box that only allows numbers to be entered, You can reload the existing edit box control class without re-writing a new control class. In MiniGUI, this technology is called subclass or window derivation. There are three subclass methods:

  • One is to subclass the created control instances, and the result of subclass is that only the control instances are affected;
  • One is to subclass A control class, which will affect all the control instances created later;
  • The last one is to register a subclass control class based on a control class, without affecting the original control class. In Windows, this technology is also called superclass.

In MiniGUI, The subclass of the control is actually implemented by replacing the existing window process. The code in Listing 4 creates two subclass edit boxes through the control class. One can only enter numbers, and the other can only enter letters:

Listing 4 control subclasses # define idc_ctrl1 100 # define idc_ctrl2 110 # define idc_ctrl3 120 # define idc_ctrl4 130 # define limit 0x0001 # define my_es_alpha_only 0x0002 static wndproc old_edit_proc; static int restrictededitbox (hwnd, int message, wparam, lparam) {If (Message = msg_char) {DWORD my_style = getwindowadditionaldata (hwnd ); /* determine the blocked button type */If (my_style & my_es_digit _ Only) & (wparam <'0' | wparam> '9') return 0; else if (my_style & my_es_alpha_only) if (! (Wparam> = 'A' & wparam <= 'Z') | (wparam> = 'A' & wparam <= 'Z '))) /* when receiving the blocked key message, the system returns */return 0;}/* Other messages processed by the old window process */Return (* old_edit_proc) (hwnd, message, wparam, lparam);} static int controltestwinproc (hwnd, int message, wparam, lparam) {Switch (Message) {Case msg_create: {hwnd hwnd1, hwnd2, hwnd3; createwindow (ctrl_static, "digit-only box:", ws_child | ws_visib Le | ss_right, 0, 10, 10,180, 24, hwnd, 0); hwnd1 = createwindow (ctrl_edit, "", ws_child | ws_visible | ws_border, idc_ctrl1, 200, 10,180, 24, hwnd, my_es_digit_only); createwindow (ctrl_static, "alpha-only box:", ws_child | ws_visible | ss_right, 0, 10, 40,180, 24, hwnd, 0 ); hwnd2 = createwindow (ctrl_edit, "", ws_child | ws_border | ws_visible, idc_ctrl2, 200, 40,180, 24, hwnd, my_es_alpha _ Only); createwindow (ctrl_static, "normal edit box:", ws_child | ws_visible | ss_right, 0, 10, 70,180, 24, hwnd, 0); hwnd3 = createwindow (ctrl_edit, "", ws_child | ws_border | ws_visible, idc_ctrl2, 200, 70,180, 24, hwnd, timeout); createwindow ("button", "close", ws_child | bs_pushbutton | ws_visible, idc_ctrl4, 100,100, 60, 24, hwnd, 0);/* replace the window process of the edit box with the custom Window Process, and save the old window process. */Old_edit_proc = setwindowcallbackproc (hwnd1, callback); setwindowcallbackproc (hwnd2, callback); break;}...} return defaultmainwinproc (hwnd, message, wparam, lparam );}

In Listing 4, the program first defines a window processing process, namely the restrictededitbox function. Then, when using the createwindow function to create a control, replace the window processing process of the two edit boxes with the restrictededitbox function defined by setwindowcallbackproc, the value returned by the function (that is, the address of the processing process of the old control window) is saved in the old_edit_box variable. After these edit boxes are created, their messages are first processed by the restrictededitbox function, and then processed by the old window in some cases.

The other two control subclass methods are not described here.

4.2 Implementation of control classes in MiniGUI

The MiniGUI function library actually maintains the data structure of all current control classes, including the control class name and the corresponding control class information. The data structure is actually a hash table. Each entry of the hash table contains a pointer pointing to a linked list of controls whose names start with a letter (case-insensitive. The structure of the control information is defined as follows:

# Define maxlen_classname 15 typedef struct _ ctrlclassinfo {char name [maxlen_classname + 1]; // control class name Program/** common properties of this class */DWORD dwstyle; // control class style hcursor; // control cursor int ibkcolor; // control background color int (* controlproc) (hwnd, Int, wparam, lparam ); // DWORD dwadddata during control processing; // int nusecount; // count, that is, the number of controls belonging to the control class in the system struct _ ctrlclassinfo * next; // The information structure of the next control class} ctrlclassinfo; typedef ctrlclassinfo * pctrlclassinfo;

The data structure of the control class contains information such as the mouse, cursor, and callback function address of the control class. When you create a control that belongs to the control class, the information is copied to the control data structure. In this way, the new control instance inherits the representation and behavior of the control class.

The hash function of the hash table is actually very simple. Its return value is the English alphabet Sequence Value of the first letter of the control class name:

Static int hashfunc (char * szclassname) {/* determine whether the first character is a letter */If (! Isalpha (szclassname [0]) return err_ctrlclass_invname;/* converts all characters to uppercase */while (szclassname [I]) {szclassname [I] = toupper (szclassname [I]); I ++; if (I> maxlen_classname) return err_ctrlclass_invlen ;} /* obtain the hash value */return szclassname [0]-'A ';}

The registration and cancellation functions of the control class are very simple and will not be described here.

4.3 implementation of controls in MiniGUI

The control structure is relatively complex. It contains the location information, control style, extended style, control mouse, icon, and control callback function address of the control in the parent window:

Typedef struct _ control {/** these members have the same structure as mainwin. */short datatype; // The short wintype used internally; // The Int left and top window types used internally; // the position of the control in the parent window: int right and bottom; int Cl, CT; // the position of the control customer area in the parent window: int Cr, CB; DWORD dwstyle; // control style DWORD dwexstyle; // control extended style int ibkcolor; // hmenu of the background color; // haccel of the menu handle; // hcursor of the acceleration key table handle; // hicon of the mouse cursor handle; // hmenu hsysmenu of the icon handle; // System menu handle HDC privcdc; // Private DC handle invrgn; // the control's invalid region pgcrinfo; // the control's global cut region pzordernode; // Z-order node // only valid pcaretinfo for controls with ws_ex_ctrlasmainwin extension style; // Insert the message DWORD dwadddata; // control the additional data DWORD dwadddata2; // control additional data int (* controlproc) (hwnd, Int, wparam, lparam); // control char * spcaption in message processing; // control title int ID; // control identifier, integer scrollbarinfo vscroll; // scrollbarinfo hscroll; // horizontal scroll bar information pmainwin; // The Main Window struct _ control * pparent containing the control; // control parent window/** child windows. */struct _ control * children; // The first child control of the control, struct _ control * active; // The current active child control, struct _ control * old_under_pointer; // The Child control with the old mouse and mouse. The members below ** are only valid for the control */struct _ control * Next; // The next sibling control struct _ control * Prev; // The previous sibling control pctrlclassinfo pcci; // pointer to the class structure of the control to which the control belongs} control; typedef control * pcontrol;

Obviously, as long as the callback function address of the control is replaced, the control can be conveniently subclass. It is worth mentioning that the structure definition of the main window is basically the same as the data structure definition of the control, but there are some slight differences between some members.

 

5. Design of the input method module

The input method provides the ability to translate standard keyboard input into appropriate languages. MiniGUI also contains standard Chinese Simplified input methods, including full spelling, five strokes, and intelligent pinyin. The Input Method of MiniGUI is a relatively independent module (called IME), which is actually a special main window. After the main window is started, register yourself as the input window. In this way, the MiniGUI desktop knows that the key information should be sent to the main window first, instead of the current active main window. When the main activity window changes, desktop notifies the input method window of the current activity window. In this way, when the input window receives the key message and translates it into appropriate characters, it can be sent to the current active window.

To implement interaction between the desktop and IME windows, MiniGUI defines the following messages for the input window. When the active window changes, MiniGUI will send these messages to the IME window:

  • Msg_ime_settarget: The target activity window of the Input Method for sending the message;
  • Msg_ime_open: send this message to the input method window. The current active window is a window with the extended style of ws_ex_imecompose, so the input method window should be displayed.
  • Msg_ime_close: This message is sent to the input method window. The current active window does not have the extended ws_ex_imecompose style, so the input method window should be hidden.

If a window is to become an input method window, you must complete the following work:

  1. Register as the current input method;
  2. Processes the message msg_ime_settarge and records the target window of the current activity;
  3. Press the translation key and send the translated structure to the target window of the current activity through the msg_char message;
  4. Processes msg_ime_open and msg_ime_close messages. The input method window is automatically displayed when you switch to the activity window for the input method.

 

6 Summary

This article focuses on the window Cut Processing Algorithm in MiniGUI. This is the first problem to be solved in any multi-window system. Then, this article introduces the implementation of control classes and controls in MiniGUI. Finally, the design idea of the Input Method window in MiniGUI is introduced.

 

Appendix: Latest Progress of MiniGUI

On June 23, lunar January 2001, version 0.9.98 of MiniGUI was released. This version includes a MiniGUI version specifically designed for embedded systems such as PDA. This version is called MiniGUI-lite. The following is a brief introduction to MiniGUI-lite. In the future, we will write an article to introduce MiniGUI-lite in detail.

As we all know, MiniGUI adopts a thread-based architecture and establishes thread-based message transmission and window management functions. However, in many systems, this thread-based structure is not very good. This is because of some well-known reasons-the Linux thread, although providing the maximum degree of data sharing, has caused the system architecture to be fragile. If a thread stops running because of illegal data access, the entire process will be affected. Contrary to the thread structure, the traditional Unix IPC mechanism is used to establish a window system, that is, a client/server system similar to X Window. This kind of architecture has its inherent shortcomings, mainly because the normal IPC Mechanism cannot provide efficient data replication, and a large amount of CPU resources are used to copy data between processes. In devices such as PDAs, this waste of CPU resources will eventually lead to a reduction in system performance and an increase in device power consumption.

To solve some problems introduced by the MiniGUI version due to threads and make MiniGUI more suitable for embedded systems, we decided to develop a MiniGUI Lite version. The purpose of this version is:

1. maintain compatibility with the original MiniGUI version at the source code level of 98% or above. 2. linuxthreads is no longer used. 3. Multiple MiniGUI Lite-based applications can be run simultaneously, that is, multiple processes, and frontend and backend processes can be switched.

Obviously, to meet the above three purposes at the same time, if the traditional C/S structure is used to transform the existing MiniGUI, it should not be difficult to achieve. However, the defects of the traditional C/S structure mentioned above cannot be avoided. After analysis on PDA and other embedded systems, we found that some pda products have the ability to run multiple tasks, but the screen at the same time for drawing programs, generally no more than two. Therefore, as long as the two processes are isolated from each other, there is no need to use a Complex C/S structure to process the mutual cut between multiple process windows. That is to say, in such a product, it is a waste to use a multi-window system based on the traditional C/S structure.

With the above understanding, we have made the following simplified design for the MiniGUI-lite version:

1. Each Process maintains its own Z-order main window, and the main windows created by the same process are cut between each other. That is to say, except that this process has only one thread and only one message loop, there is no difference between it and the original MiniGUI version. Each process does not need to consider other processes when drawing the screen. 2. Establish a simple customer/server system, but ensure that data replication between processes is minimized. Therefore, data transmitted between the server and the customer is limited to the input data of the input device and some request and response data between the customer and the server. 3. There is a server process (mginit) That initializes some input devices and sends messages from the input devices to the MiniGUI lite client process at the front end through Unix domain sockets. 4. The server and the customer are respectively limited to draw in two non-Intersecting rectangles on the screen. At the same time, only one customer and the server can draw the screen. Other customers can continue to run, but the screen input is blocked. The server can use the API to switch a customer to the foreground. At the same time, the server and the customer use signals and System V semaphores for synchronization. 5. The server also uses the system v ipc Mechanism to share some resources, including bitmaps, icons, mouse, and fonts, to reduce the actual memory consumption.

Now you can use MiniGUI-Lite to run more than one MiniGUI application at a time. We can start other MiniGUI programs from a program called "mginit. If the customer terminates for some reason, the server can continue to run. In our release version, there is a software package called mglite-exec, which contains an mginit program that creates a virtual console window. We can start other programs in the software package from the command line of the virtual console, or even debug these programs through GDB.

We can create multiple windows in the MiniGUI-lite program, but cannot start a new thread to create a window. This is the biggest difference between MiniGUI-lite and MiniGUI. In addition, almost all other APIs are compatible with the original MiniGUI version. Therefore. Porting from the original MiniGUI version to the MiniGUI-lite version is very simple. Do not believe it. Check the program in the mglite-exec package. All the programs are from the miniguiexec package, and the changes to each source file cannot exceed 5 lines.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.