PCSX2 Documentation/WxWidgets Coding Strategies: Difference between revisions

Update.
(Update.)
 
(9 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<center>{{Warning|<big>'''This guide is outdated as PCSX2 now uses Qt!'''<br/>Please refer to the PCSX2 Discord server if you wish to help with programming.</big>}}</center>
==Guidelines==
==Guidelines==
The wx-based codebase for PCSX2 is designed to 'lean' heavily on wxWidgets, meaning that PCSX2 will whenever possible use wx-provided tools and classes instead of re-inventing our own. This decision was made as it allows us take full advantage of the cross-platform tools offered by wxWidgets, which ensures more correct behavior on Windows and Linux alike and, in turn makes life simpler for all PCSX2 developers.
The wx-based codebase for PCSX2 is designed to 'lean' heavily on wxWidgets, meaning that PCSX2 will whenever possible use wx-provided tools and classes instead of re-inventing our own. This decision was made as it allows us take full advantage of the cross-platform tools offered by wxWidgets, which ensures more correct behavior on Windows and Linux alike and, in turn makes life simpler for all PCSX2 developers.
Line 60: Line 61:


There are several ways to send events between windows in wxWidgets, and only one of them is typically the ''correct'' way:
There are several ways to send events between windows in wxWidgets, and only one of them is typically the ''correct'' way:
<nowiki>
<source lang="cpp">
    // This method ensures cross-platform consistency and thread safety, but cannot be
// This method ensures cross-platform consistency and thread safety, but cannot be
    // used to get a return code.
// used to get a return code.
    myWidget->GetEventHandler()->AddPendingEvent( evt );
myWidget->GetEventHandler()->AddPendingEvent( evt );


    // This one performs an immediate handling of the event, and should only be used
// This one performs an immediate handling of the event, and should only be used
    // if you need a return code, or know for sure the caller is on the Main/GUI thread
// if you need a return code, or know for sure the caller is on the Main/GUI thread
    myWidget->GetEventHandler()->ProcessEvent( evt );
myWidget->GetEventHandler()->ProcessEvent( evt );
 
// The wxApp class does not have a GetEventHandler() so for it you use this:
wxGetApp()->AddPendingEvent( evt );    // safe from any thread
wxGetApp()->ProcessEvent( evt );      // safe form GUI thread only
</source>


    // The wxApp class does not have a GetEventHandler() so for it you use this:
    wxGetApp()->AddPendingEvent( evt );    // safe from any thread
    wxGetApp()->ProcessEvent( evt );      // safe form GUI thread only
</nowiki>
This can be a bit confusing because wx has several other options for sending events, and most of them have caveats as noted below:
This can be a bit confusing because wx has several other options for sending events, and most of them have caveats as noted below:
<nowiki>
    // This one works but is depreciated, and can lead to cross-platform inconsistencies:
    myWidget->AddPendingEvent( evt );


    // This one has the same problem as above.
<source lang="cpp">
    wxPostEvent( myWidget, evt );
//This one works but is depreciated, and can lead to cross-platform inconsistencies:
myWidget->AddPendingEvent( evt );


    // This one actually works correctly, but might as well just use the more direct
//This one has the same problem as above.
    // example of myWidget->GetEventHandler()->AddPendingEvent( evt );
wxPostEvent( myWidget, evt );
    wxPostEvent( myWidget->GetEventHandler(), evt );
 
</nowiki>
// This one actually works correctly, but might as well just use the more direct
... So the moral of the story is: Use <code>GetEventHandler()</code> when possible (basically anything except the <code>wxApp</code> object), and use <code>AddPendingEvent()</code> unless you need a return code ''and'' know you're on the main GUI thread.
// example of myWidget->GetEventHandler()->AddPendingEvent( evt );
wxPostEvent( myWidget->GetEventHandler(), evt );
</source>
 
... So the moral of the story is: Use <code>GetEventHandler()</code> when possible (basically anything except the <code>wxApp</code> object), and use <code lang="cpp">AddPendingEvent()</code> unless you need a return code ''and'' know you're on the main GUI thread.


==Guidelines when Using Windows/Linux Specific Code==
==Guidelines when Using Windows/Linux Specific Code==


The simple rule is to not use any windows or linux specific code unless absolutely necessary. Most of the time _wxWidgets_ provisions us with cross-platform alternatives for most tasks, so always make sure to check the wx documentation first. But, of course, there are still cases of advanced coding that wx doesn't cover, and these will need platform specific implementations. For example, there is no direct Linux equivalent of Windows Structured Exception Handling (SEH), and PCSX2 code that uses SEH must either be coded to use Linux signals (if possible) or `#ifdef`'d out under Linux.
The simple rule is to not use any windows or linux specific code unless absolutely necessary. Most of the time ''wxWidgets'' provisions us with cross-platform alternatives for most tasks, so always make sure to check the wx documentation first. But, of course, there are still cases of advanced coding that wx doesn't cover, and these will need platform specific implementations. For example, there is no direct Linux equivalent of Windows Structured Exception Handling (SEH), and PCSX2 code that uses SEH must either be coded to use Linux signals (if possible) or <code>#ifdef</code>'d out under Linux.


===There are two ways to handle separate Windows and Linux implementations===
===There are two ways to handle separate Windows and Linux implementations===


* Create two separate files, one under /Windows and one under /Linux, that each implement a function as according to the platform needs. _(preferred)_
* Create two separate files, one under /Windows and one under /Linux, that each implement a function as according to the platform needs. ''(preferred)''
* Use inline #ifdefs to separate behavior. _(useful for very simple/short differences)_
* Use inline #ifdefs to separate behavior. ''(useful for very simple/short differences)''


As noted, it's generally preferred to create implementations in platform specific files over using `#ifdef`. This helps keep code much cleaner and saner, and is more friendly toward code editors/IDEs as well (most editors handle `#ifdef` poorly, either failing to gray out the unused defines, or by enforcing an ugly tabbing layout that is only suited to function-level codeblock removal). When using platform specific files it's usually preferred to have each filename assigned the platform's tag. Example:
As noted, it's generally preferred to create implementations in platform specific files over using <code>#ifdef</code>. This helps keep code much cleaner and saner, and is more friendly toward code editors/IDEs as well (most editors handle <code>#ifdef</code> poorly, either failing to gray out the unused defines, or by enforcing an ugly tabbing layout that is only suited to function-level codeblock removal). When using platform specific files it's usually preferred to have each filename assigned the platform's tag. Example:
```
<source lang="bash">
    /Windows/WinSpecific.cpp
/Windows/WinSpecific.cpp
    /Linux/LnxSpecific.cpp
/Linux/LnxSpecific.cpp
```
</source>
... as this provides a clear identifier to cross-platform programmers which files they're looking at when they use things like Find-in-Files and other global search tools.
... as this provides a clear identifier to cross-platform programmers which files they're looking at when they use things like Find-in-Files and other global search tools.
{{PCSX2 Documentation Navbox}}
ninja
3,396

edits