I would like to know how window(not just for Windows OS, but general window based approach ) user interface organized ? Here means how it is designed from architectual point of view with details on each aspect of it. Also, it will be very good to have some code examples, even if that is pseudo one.

The wiki has some great resources for that (also check the links to tutorials at the bottom).

Btw, there's no simple answer to your question. Depends how you'd like to implement your GUI. The first thing you should decide, how you want to redraw windows. There are two main approches. First one leaves the task entirely to the process, in which the GUI sends a redraw event (see X11 Expose) to the process which has created the window. This is the older model, and works fine on machines with limited RAM. The second approach is to store a pixmap in the GUI of all windows, and compose them into a desktop screen (therefore such a GUI is called a compositor). This is the newer model, and all mainstream OS use this as of 2019. With proper video card driver, you can use the GPU's memory for storing the windows pixmaps, which also speeds up composition and makes certain effects effective (semi-transparent windows, whobbling etc.). The X11 server is a bit both, as by default it uses Expose events, but with modules it can be turned into a compositor, see xcompmgr for example. A plain compositor approach would be Wayland.

Now if you have decided how windows are handled, you have to go on with drawing primitives and widgets (menus, buttons, etc.). Some OS use a built-in interface for that (like Windows and Menuet), while others simply delegate the task to a user library (therefore have many implementations, like wxWidgets, GTK, QT etc.). As a matter of fact, old Windowses (95/98/XP) had the renderer so hardwired in the kernel, that you could prevent a process from running just by constantly moving around its window.

The combination of these two (redraw/compose, server/user side renderer) gives 4 totally different GUI architectures, and there are many other things you can take into account.

I try to get this out to all new members, either in a thread or in a PM, to get everyone started on the same footing. I hope this helps.

----------------------------------The first thing I want to say is this: if you aren't already using version control for all software projects you are working on, drop everything and start to do that now. Set up a VCS such as Git, Subversion, Mercurial, Bazaar, or what have you - which you use is less important than the fact that you need to use it. Similarly, setting up your repos on an offsite host such as Gitlab, Github, Sourceforge, CloudForge, or BitBucket should be the very first thing you do whenever you start a new project, no matter how large or small it is.

If nothing else, it makes it easy to share your code with us on the forum, as you can just post a link, rather than pasting oodles and oodles of code into a post.

Once you have that out of the way (if you didn't already), you can start to consider the OS specific issues.

If you haven't already, I would strongly advise you to read the introductory material in the wiki:

I strongly suggest that you read through these pages in detail, along with the appropriate ones to follow, before doing any actual development. These pages should ensure that you have at least the basic groundwork for learning about OS dev covered.

This brings you to your first big decision: which platform, or platforms, to target. Commonly options include:

x86 - the CPU architecture of the stock PC desktops and laptops, and the system which remains the 'default' for OS dev on this group. However, it is notoriously quirky, especially regarding Memory Segmentation, and the sharp divisions between 16-bit Real Mode, 16-bit and 32-bit Protected Modes, and 64-bit Long Mode.

ARM - a RISC architecture widely used on mobile devices and for 'Internet of Things' and 'Maker' equipment, including the popular Raspberry Pi and Beagleboard single board computers. While it is generally seen as easier to work with that x86, most notably in the much less severe differences in between the 32-bit and 64-bit modes and the lack of memory segmentation, the wiki and other resources don't cover it nearly as well (though this is changing over time as it becomes more commonly targeted).

MIPS, another RISC design which is slightly older than ARM. It is one of the first RISC design to come out, being part of the reason the idea caught on, and is even simpler than ARM in terms of programming, though a bit tedious when it comes to assembly programming. While it was widely used in workstations and game consoles in the 1990s, it has declined significantly due to mismanagement by the owners of the design, and is mostly seen in devices such as routers. There are a handful of System on Chip single-board computers that use it, such as the Creator Board and the Onion Omega2, and manufacturers in both China and Russia have licensed the ISA with the idea of breaking their dependence on Intel. Finding good information on the instruction set is easy, as it is widely used in courses on assembly language and computer architecture and there are several emulators that run MIPS code, but finding usable information on the actual hardware systems using it is often difficult at best.

RISC-V is an up and coming open source hardware ISA, but so far is Not Ready For Prime Time. This may change in the next few years, though.

You then need to decide which Language to use for the kernel. For most OS-Developers this means knowing and using C; while other languages can be used, it is important to know how to read C code, even if you don't use C, as most OS examples are written in it. You will also need to know at least some assembly language for the target platform, as there are always parts of the kernel and the device drivers which cannot be done in high-level languages.

You further need to choose the compiler, assembler, linker, build tool, and support utilities to use - what is called the 'toolchain' for your OS. For most platforms, there aren't many to choose from, and the obvious choice would be GCC and the Binutils toolchain due to their ubiquity. However, on the Intel x86 platform, it isn't as simple, as there are several other toolchains which are in widespread use for it, the most notable being the Microsoft one - a very familiar one to Windows programmers, but one which presents problems in OSDev. The biggest issue with Visual Studio, and with proprietary toolchains in general, is that using it rules out the possibility of your OS being "self-hosting" - that is to say, being able to develop your OS in the OS itself, something most OSdevs do want to eventually be able to do. The fact that Porting GCC to your OS is feasible, whereas porting proprietary x86 toolchains isn't, is a big factor in the use Binutils and GCC, as it their deep connection to Linux and other Unix derivatives.

Regardless of the high-level language you use for OS dev (if any), you will still need to use assembly language, which means choosing an assembler. If you are using Binutils and GCC, the obvious choice would be GAS, but for x86 especially, there are other assemblers which many OSdevs prefer, such as Netwide Assembler (NASM) and Flat Assembler (FASM).

The important thing here is that assembly language syntax varies more among the x86 assemblers than it does for most other platforms, with the biggest difference being that between the Intel syntax used in the majority of x86 assemblers, and the AT&T syntax used in GAS. You can see an overview of the differences on the somewhat misnamed wiki page Opcode syntax. While it is possible to coax GAS to use the Intel syntax using the .intel_syntax noprefix directive, the opposite is generally not true for Intel-based assemblers such as NASM, and even with that directive, GAS is still quite different from other x86 assemblers in other regards.

It is still important to understand that the various Intel syntax assemblers - NASM, FASM, and YASM among others - have differences in how they handle indexing, in the directives they use, and in their support for features such as macros and defining data structures. While most of these follow the general syntax of Microsoft Assembler (MASM), they all diverge from it in various ways.

Once you know which platform you are targeting, and the toolchain you want to use, you need to understand them. You should read up on the core technologies for the platform. Assuming that you are targeting the PC architecture, this would include:

We generally don't recommend designing your own, but as with boot loaders, it is a possibility as well.

While this is a lot of reading, it simply reflects the due diligence that any OS-devver needs to go through in order to get anywhere. OS development, even as a simple project, is not amenable to the Stack Overflow cut-and-paste model of software development; you really need to understand a fair amount of the concepts and principles before writing any code, and the examples given in tutorials and forum posts generally are exactly that. Copying an existing code snippet without at least a basic idea of what it is doing simply won't do. While learning itself is an iterative process - you learn one thing, try it out, see what worked and what didn't, read some more, etc. - in this case a basic foundation is needed at the start. Without a solid understanding of at least some of the core ideas before starting, you simply can't get very far in OS dev.

Hopefully, this won't scare you off; it isn't nearly as bad as it sounds. It just takes a lot of patience and a bit of effort, a little at a time.

_________________Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTFμή εἶναι βασιλικήν ἀτραπόν ἐπί γεωμετρίανLisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.

As stated before, a GUI or a windowing system, is a big project and requires a lot of work. If I may, here are a few suggestions.

Do not rely upon any set screen size or pixel depth, nor rely on a single form of screen drawing. Your windowing system should not care what it is actually being displayed to nor in what shape, size, or pixel depth.

"Draw" all objects to a single "screen buffer" using a known pixel depth, say 32-bits. Then tell the drawing routine that a certain area of this "screen buffer" is dirty and let it draw to the physical screen. It will convert the 32-bit pixels to 24, 16, 15, 8, 4, whatever pixel depth and type of display.

Each item on the screen is an object. A window is the main object for that app or thread. This window is only a rectangle (or circle or whatever shape you want) and is drawn as a simple single color rectangle. Then, this window object has child objects. A Title Bar, which has a title, various buttons within that title bar, a border object, which might contain a resize button object, a menu, button bar, status bar, etc. Each of these objects are children of the Window object. Each child object only knows about the parent. For example, if you have a button 10 pixels from the left, and 10 pixels from the top, this button's coordinates is 10,10. Period. It knows only of the parent window. When the parent window is moved (or created), it calls any child object's handler to draw that child, which queries its parent for the location, 10,10 from the parent's left/top position.

Every object has a parent, except for the root object. Every object may or may not have a child object. Every object is listed within its parents node list so that the parent can keep track of all of its children. This list is sorted so that the first (or last) entry is the topmost entry. i.e.: It is displayed last so that it is on top.

Note that the root object will have multiple Window objects as its children. Hence the order of the node list gives you which (child) Window is on top and has control.

Keep all items as objects and none of them rely upon any other object except for a parent object. i.e.: one button in the same sibling list does not care where or what another button is. Along those lines, any child object of one parent has absolutely no care or knowledge of a child object in another parent list. Any object is self contained as long as it has access to its parent.

Now, with this in mind, you will need to know what is a parent and what is a child.

Let's say you have an text editor type object, such as this object I am currently typing in. It's parent is not the window object, but the scroll object you see to the right. The parent has a child that is a scroll object, then that scroll object has multiple children. This way, you can adjust where to start displaying the children objects.

One last thing, you need some sort of a messaging system. For example, when I press the "Submit" button below, that button needs to tell the parent to do something. Each object will have a messaging system, allowing you to send a message to other objects. You send this message to the parent object with instructions to which object (or objects) receive this message. An object can only send a message to its parent, no further. It is up to the parent to send it beyond that.

One of my books within my Book Series explains this in more detail with source code. I have a few examples on that specific page.

Question to BenLunt: when you say about messaging system between child and parent, what is most efficient way of organizing it in your opinion ? pipe, shared memory, ... ?

It is up to you how you do it. There are pros and cons to all types.

I currently send a small packet of information to the parent, or to the object (from the parent). This small packet has two parameters: The first is the command, which can be anything specific to the data being sent. The second is a pointer to a memory structure specific to the command being sent.

The thing to remember though is that when the parent sends this packet, it sends it down the stream of objects until one of the objects answer. For example, if the parent sends the message to a button control, this button control could be a user-drawn button and will accept the message, draw the button (or whatever) and return an answer. If this is a standard button, the button control will ignore the message and let the underlining standard button code draw the button.

Another thought: Even though you might not notice, most items on the screen are buttons. A list is just a list of buttons, simple drawn differently (no borders). A menu is just a string of buttons on a background. A URL link is just a button, drawn with text only. A checkbox is just a button, drawn with a box on the left or right and text instead of text within a box (border).

Most items are just buttons, simply drawn differently. Write your code so that you may easily set the "handler" code for a button and that handler is called for all drawing, click, dbl click, etc., messages. That handler is what takes care of the calling of the correct drawing function (a standard button, a check box, a radio button, a URL link, etc.).

The code included with Volume 6 of my series shows this in some detail.

I want to add another example for you, and anyone else reading wanting to create a GUI.

Have a look at the menu in the lower right of the following example screen shot:

There is a menu object that simply contains three buttons: FILE, EDIT, HELP. They just happen to be side by side instead of up and down. The parent object is the Window object, which has the menu as a child object, which this menu object has three children, the three mentioned buttons. These buttons have no idea or care where they are located. It is up to the menu object to place them within the menu. A flag, MENU_HZ or MENU_VT, indicates whether to place them side by side or up and down. Period. That is all that object does. It has no idea of anything else.

When the FILE button is clicked, it creates a menu object, placing eleven (11) button objects in it, now with the MENU_VT flag set. Why eleven when you only see eight (8) items? Have a closer look. There are three (3) divider lines. These are actually buttons, though they are inactive, so that the user cannot click on them. This makes it so easy to display a menu simply because you give a list of button objects. It just so happens that three (3) of these button objects are drawn differently, due to the handler override within its button handler code.

See, it is actually easier than you might think. Keeping it simple makes it a lot easier to code.

To display images to the left of the text, a flag can be stored in the button object with a pointer to an image object. If the pointer is NULL, no image is given. However, notice that within the listed example above, the eleven (11) object menu is shifted right to allow the images. Notice that the sub menu, the one with FILE 0 and FILE 1, is not shifted right for images. Your display code will need to scroll through all button objects within this menu object to check if any of them point to an image object. If at least one of them does, display each button shifted to the right. If none of them point to an image object, i.e.: all pointers are NULL, no need to shift to the right. By doing this you also can decide how wide the menu background object will be. By scrolling through all button objects within the menu, you can grab the length of the widest (or tallest) button and adjust the menu background to compensate.

One of the more difficult items to code is when a button is clicked that is a child of a menu object. Your menu object must receive the button click message before the button object does. This way it knows to destroy the menu object and any button objects that are contained within it. *However*, don't destroy the button objects until after you have called the button handler of the button that was clicked. i.e.: the parent (which is the menu object) grabs the button click message, calls the child button's handler, so that on return the menu object regains control so that it can destroy the button object. One more thing, you need to pass a message to the parent object of the menu in case this is a sub sub-menu. Any menu must send a message to its parent so that if its parent is a menu, it can too destroy itself and any sub menus it created. The main parent, in this case the Window object, will simply ignore the "menu destroy" message since it is not a menu.

With this in mind, when an object receives a "Destroy" message, it must send this message to all of its children *before* it destroys itself, *and* if any of these children have children, they also need to be sent this message. This way, for example, when the EXIT button is clicked, you can simply send a "Destroy" message to the main Window Object and it will trickle down to all objects destroying (freeing) all child objects until finally only the Window object remains, finally destroying itself.

Who is online

Users browsing this forum: No registered users and 6 guests

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum