# Opera core object

## What purposes does the Opera core object have?

This lists the primary purposes of the Opera core object:

- Initialization of the modules
- Destruction of the modules
- Storage of the global variables
- Scheduling of when to run Opera

## How to initialize the Opera object

How you create and destroy the global Opera object depends on if FEATURE_STATIC_OPERA_OBJECT is turned on. For static Opera you can do like this:

    	Opera::StaticInit();
    	g_opera->SetListener(some_listener);
    	TRAPD(status, g_opera->InitL());

    	if (OpStatus::IsSuccess(status))
    	{
    		...

    		loop:
    			g_opera->Run();

    		...
    	}

    	g_opera->Destroy();

and if FEATURE_STATIC_OPERA_OBJECT is NO, yo do:

    	g_opera = new Opera();
    	g_opera->SetListener(some_listener);
    	TRAPD(status, g_opera->InitL());

    	if (OpStatus::IsSuccess(status))
    	{
    		...

    		loop:
    			g_opera->Run();

    		...
    	}

    	g_opera->Destroy();
    	delete g_opera;

Note that the global Opera object should be destroyed the same way regardless of whether Opera::InitL() succeeded and Opera was actually run.

## How does a module add a module object to Opera?

Each module can have its own space in the Opera core object. For the module xxx the member `g_opera->xxx_module` can be made available. Each module object has to implement the interface `OperaModule`, which more or less has the two functions `InitL`() and `Destroy()`.
The implementation of the `OperaModule` shall be put in a file called xxx_module.h in the root of the xxx-module. Since the module object may not always be enabled a define will have to be set, XXX_MODULE_REQUIRED, for the module object to be included. The name of the module object shall be the name of the module capitalized, underscores removed and following character capitalized.
Example:
spatial_navigation becomes SpatialNavigationModule
webforms becomes WebformsModule

## How is a global variable added?

The module objects will be publically available through the g_opera object. To be able to easily access a member of a module object a `#define` is the best thing to use. See the coding standard on the subject of global variable naming.
The variable can be initialized in the constructor of the module object, constructed in the `InitL()` function and finally destroyed in the `Destroy()` function. Don't use the destructor to destroy the variables - use `Destroy()`.
Example:
The module foo gets a new global variable:

    class FooModule : public OperaModule
    {
    public:
    	...

    	Foo* foo;
    };

    #define g_foo g_opera->foo_module.foo

## Example of module object file

In the following code, we assume that we have a module called xxx which is turned on if FEATURE_XXX is turned on, and is controlled by the define XXX_SUPPORT.
File: xxx_module.h:

    /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
    **
    ** Copyright (C) 1995-2005 Opera Software AS.  All rights reserved.
    **
    ** This file is part of the Opera web browser.  It may not be distributed
    ** under any circumstances.
    */

    #ifndef XXX_MODULE_H
    #define XXX_MODULE_H

    #ifdef XXX_SUPPORT

    #include "modules/hardcore/opera/module.h"

    #define XXX_MODULE_REQUIRED

    class XxxHandler;

    class XxxModule : public OperaModule
    {
    public:
    	void InitL(const OperaInitInfo& info);
    	void Destroy();

    	XxxHandler* handler;
    };

    #define g_xxx_handler g_opera->xxx_module.handler;

    #endif // XXX_SUPPORT

    #endif // !XXX_MODULE_H

## How does the scheduling work?

The Opera object has a `Run()`-function which is the most important function to be able to make Opera do something. Calling `Run()` will make Opera handle one internal message and then return again. The result of the call will be the time in milliseconds until the next time Opera wants to be called. The product can then set a platform timer event to wait for that time. If the return value is zero it means there are more messages which would like to be handled as soon as possible. It is important to know that Opera can return zero for a long period of time, so it may not be a good solution to always let Opera run if it returns zero. The platform must be able to provide user input and network input from time to time too.
Since Opera sometimes is called from the platform interface layer, for example when receiving network input or keyboard input, it can happen that the time when Opera was scheduled to be run the next time is not valid anymore. If this happens, the `OnReschedulingNeeded()` function in the listener object will be called. This means the product must reset the timer for when Opera is to be run the next time.
Here follows an example implementation, similar to that used on Windows in the WinGogi port:

    void
    ProductModule::OnReschedulingNeeded(int next_event)
    {
    	m_next_timer = next_event;
    	SetTimer(g_hwnd, 0, m_next_timer, NULL);
    }

    void
    ProductModule::MainLoop()
    {
    	// Main message loop:
    	MSG msg = {0};
    	while (true)
    	{
    		BOOL handle = FALSE;
    		if (m_next_timer == 0)
    		{
    			if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    				handle = TRUE;
    			else
    			{
    				m_next_timer = g_opera->Run();
    				if (m_next_timer > 0)
    					SetTimer(g_hwnd, 0, m_next_timer, NULL);
    			}
    		}
    		else
    		{
    			if (!GetMessage(&msg, NULL, 0, 0))
    				break;
    			handle = TRUE;
    		}

    		if (handle)
    		{
    			if (msg.message == WM_QUIT)
    				break;

    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
    }

`PeekMessage()` looks at the Windows message queue and returns TRUE if there is a message available in the queue. `GetMessage()` blocks until a message is available in the message queue. Will return FALSE if the application is quitting. `TranslateMessage()` and `DispatchMessage()` are used to handle the message.
This implementation will keep handling Windows messages until there are no available, then it will start running Opera. This makes sense if you want to make sure user input, network traffic etc is always taken care of as soon as possible.