This page is aimed to help people convert Camelot code designed for MSW to work on wxWidgets. Most of this you'll find in the wxOil directory.

Things to bear in mind when porting code that hasn't been compiled for wxWidgets before

If you're compiling a Camelot file that hasn't been ported to wxWidgets before (some of the stuff in svn doesn't compile right now), here are some things to remember.
  1. Run Scripts/ on the file. This will fix up most things (honest). Things it will fix include:
    • Line endings (should be LF not CRLF)
    • Ensuring there is an LF at the end of the file
    • TRACE statements
    • ERROR statements
    • Resource identifiers (99% of the work)
    • Types (removes deprecated types and puts in new types)
    • Author email addresses
    • Copyright notice
    • SVN version header (and remove RCS header)
    • Optoken handling
    • Key handling
  2. If breaks your file, do not say "oh well", revert and move on. Make it so that it doesn't break it. This is because the script is regularly run on ALL files. The two most common things you want it to do is not to convert a certain deprecated type (e.g. when overriding a virtual method using 'long' in wx), or where OpDescriptors make up resource IDs using '##' ( is not sufficiently smart to work out how to unscramble these). In the first case, put '/*TYPENOTE: Correct*/' next to the 'long' (or other deprecated type). In the second case, put '/*NORESOURCEFIX*/' next to the line.
  3. Resource IDs are no longer compile-time constants. This means you cannot use them as operands to 'case' inside a switch statement. Unroll the switch statement into an if, else if, else if, etc. clause. The resources system is explained here.
  4. Ocassionally  you something like Foo::Bar::Baz failing to compile. This is normally element Baz of an enum Bar in a class Foo failing to compile. Use Foo::Baz instead.
  5. Do not use VK_FOO. Use CAMKEY_FOO.
  6. Most errors about forward references to OpDescriptor and OpHistory can be fixed by including opdesc.h or ophist.h (as appropriate) - they are no longer in the precompiled headers.
  7. If you see "char" being used, it is almost certainly wrong. Check first, then convert to TCHAR. Similarly, string constants need enclosing in _T(). This also means you need to convert the relevant string functions to their TCHAR equivalent (so they work on both unicode and non-unicode builds). The easiest way to find them is to see what TCHAR function is #define'd to them on a non-unicode build in camtypes.h, then use that. Note some (unsafe) functions don't exist.
  8. Ensure your class member variables are initialized in the same order that they are declared, or you will get warnings.
  9. Ensure your case statements either list every case for an enum, or you have a default clause (even if it just has a "break;").
  10. Do not use '///'. Do not use '???'. Do not use '/*' inside a comment block. All these produce warnings (except the first, which is highlighted a different colour in most editors with syntax highlighting).
  11. All the indenting should be reasonably OK. If it's really bad, the following may help (but don't run it unless the file is really broken because it sometimes makes things worse):
    • indent -gnu -bad -bap -bbb -bbo -bls -bli0 -cdw -cli4 -cbi0 -cp49
      -c65 -cd49 -di0 -i4 -l94 -lc94 -lp -ip0 -npsl -nbc -ncs -npcs
      -pi4 -saf -sai -saw -ut -ts4 <filename>
  12. All dialogs have already been converted (at least as a first cut - redesign them properly and to use sizers at your leisure). Infobars need more thinking about. There are perl programs to do this automatically. This will be far quicker than doing it yourself.
  13. Do not take the address of temporaries (e.g. return values from functions). It may have worked under MSVC. It doesn't (reliably) under gcc. Put them into an automatic (a local), and take the address of that. Ensure the reference is not used outside the scope of the automatic.
  14. Various unions have gone. The most common is myCoord.lox, myCoord.loy, myCoord.hix, myCoord.hiy need to be rewritten as myCoord.lo.x, myCoord.lo.y, myCoord.hi.x, myCoord.hi.y (respectively)
  15. Infobar initialization is very different. Look at an existing tool.
  16. If you find a Windows specific functions being called in the Kernel, do NOT yield to temptation and simply change them into wx functions. Do the right thing, and encapuslate them in an Oil class.
  17. Sometimes the MS-Windows functionality you need won't exis on wxWidgets, and you may need to create a new wx class. If so, consider whether it can be contributed back to the wx community (under the wxWindows license). This means you need to use the wx programming guidelines (and types) and not the Camelot ones. It also means you can't use any Camelot data types, error reporting, etc. (which may make it hard). But it can be contributed to a wider community which means it will no doubt get more people supporting it. If you can do this, put your file in the wxXtra directory. If not, use wxOil.
  18. Before you check your file in please check it for warnings. Compile with -Werror to make compilation stop on an error. Common irritants are variables that may be used unitialized, and unused variables. Please fix these. Even if they aren't "real" bugs, having warnings there on a correct compile makes the warnings useless for others, which masks real bugs.
  19. Fix up documentation where necessary, as well as code
  20. So you remembered to run Scripts/ Good. Just checking.


A quick conversion table 

The purpose of this table is present a list of MFC type objects and their (rough) wxWindows equivalents. The MFC objects are listed in the left-hand column and the wxWindows equivalents are listed next column.

CRect wxRect  
CWindow::GetClientRect rect.x = rect.y = 0;
GetClientSize( &rect.wight, &rect.height );
CWindow::GetWindowRect rect = wxWindow::GetRect();
wxRect   rect( GetRect() );




SetCapture CaptureMouse  

GetSysColor wxSystemSettings::GetColour  
InvalidateRect Refresh  
SetWindowText SetTitle  
TreeView wxTreeCtrl  
HTREEITEM wxTreeItemId  
HIMAGELIST wxImageList *  
::ShowWindow wxWindow::Show  
::IsWindowVisible(WindowID) wxWindow::IsShown()  
GetDlgItem wxWindow::FindWindow  
MoveWindow wxWindow::SetSize  
BringWindowToTop wxWindow::Raise  
EnableWindow Enable  
TreeView_InsertItem wxTreeCtrl::InsertItem  
TreeView_SetImageList wxTreeCtrl::SetImageList  
TreeView_Expand wxTreeCtrl::Expand  
TreeView_GetNextItem( *, *, TVGN_NEXTVISIBLE) wxTreeCtrl::GetNextVisible  
HCURSOR wxCursor *  
HANDLE wxCondition * Event objects

ios::_Openprot 0 ANSI standard does not support opening protection for streams
String constants _T("….") or wxT("…") I use _T in kernel and _T or wxT in wxOil (but they are interchangable)
GetSystemMetrics wxSystemSettings::GetMetric  


EndDialog wxWindow::EndModal  
::SetCapture wxWindow::CaptureMouse  
::ReleaseCapture wxWindow::ReleaseMouse  



Debugging under Linux

Here are some useful tips for debugging under Linux

I hit a breakpoint / SEGV / other crash and my debugger hangs. Why? Help?

This normally happens during a drag operation. What has happened is that the mouse window is "captured". wxWidgets has called gdk_pointer_grab, which has in turned called XGrabPointer. The application being debugged now has exclusive access to pointer movements and the X event queue. But (as it's hit a breakpoint etc.) is stopped. The debugger then cannot get access to these resources, and is frozen.

Here are some tips for getting out of this situation and avoiding it the future.

1.    Killing the debugged process

First, see if CTRL-ALT-[numpad /] or CTRL-ALT-[numpad *] work (for why, see below). If not, press CTRL-ALT-F1 to return you to a text mode virtual terminal (it may take a few seconds). Log in (if you haven't already), and type:

	killall XaraLX
killall gdb

This should kill both XaraLX off, and the debugger (as the process is being traced, it won't die until the debugger dies it seems). Now press CTRL-ALT-F7 to return you to your X-Windows VT. You are back with a working X-Windows session, but you've lost the information about why the program crashed. So read on, for how to avoid this.

2.    Allowing debugging during drag
Modern X servers allow certain key sequences to either release pointer capture, or kill the process with a captured pointer. The keystrokes for this are CTRL-ALT-[numpad /] or CTRL-ALT-[numpad *] respectively. So, if you hit a "frozen" state, you can hit CTRL-ALT-[numpad /] and you will be in able to debug just like normal. Of course the pointer will no longer be captured so the program may perform differently (if you need to debug in capture mode, try one of the other mechanisms below). Unfortunately, most distributions do not have these features turned on by default (that would make life too easy). In order to turn them on, you need to edit your XServer configuration file. This will be called xorg.conf or XF86Config and is normally found in the /etc/X11 directory. You need to add two lines the the section called ServerFlags (and add the section itself if it's not already there). It should look like the following:
Section "ServerFlags"
[anything that was there before you started editing this file]
Option "AllowDeactivateGrabs" "true" 
Option "AllowClosedownGrabs" "true"

You will need to restart your X-Server after this edit.

Note that the X Screensaver uses pointer grabbing to prevent people from using the terminal. If your screensaver does not communicate properly with your XServer to disable these keys, the above may represent a security risk (in that some passer by could come past your terminal with a password locked screensaver and remove it with the appopriate keystroke). Modern screensavers should not have this problem.

3.    Running your debugged process on a different X-Server
You can run the debugged process on a different X-Server merely by ensuring the environment variable "DISPLAY" is set to point to a different server (note this is not the same as a different workspace on the same X-Server). That way, the grab will be constrained to the X-Server which is running the debugged process. This will also help you if you are debugging tricky redraw problems. First of all you need to ensure you are running two X-Servers. These can use different graphics cards (and, potentially, different keyboards and mice) but setting that up is beyond the scope of this note. To share the same monitor etc.,  you need to attach a second X-Server to an additional virtual terminal (VT). This depends on your distribution, but if you are running a Gnome based distribution, there is a control panel to configure it (I'm sure KDE has an equivalent). On Ubuntu, this can be reached through the "System" menu, then choose "Administration" and "Login screen startup". On Redhat, chose "Applications", then "System Settings", then "Login Screen". Add another X-Server with ID "1", of type "Standard". Sadly you will then need to quit X and restart. You don't need to actually reboot, just quit X. CTRL-ALT-F8 takes you to your new X-Server (which will quite likely have no themes set up), and CTRL-ALT-F7 back to your normal one. Note you should log in on the new X-Server so you have the correct authentication cookies to display windows on it. Now, in your favourite IDE (running on the normal display) set the DISPLAY environment variable to be ":1.0" (in Kdevelop, it's on the "Run" pane of "Project Options"). Now when you launch the debugger, it will run the application on the other screen. Sadly, switching screens can be a bit slow and clunky.
4.    Running your debugged process on a different X Server INSIDE your current X-Server

If you don't like switching back and forward, you can run your debugged process in a "virtual" X-Server. xnest provides a virtual XServer which forwards the X drawing primatives to an X-Client running on the same machine. So you see an X windows environment running inside a window of its own. I haven't managed to get authentication to work properly with xnest (I think you need to get xauth and xdcmp running in listen mode) so I turn of authentication in the nested server when doing this. This is theoretically dangerous if other people have accounts on your machine. You have been warned. To set up xnest running on :1 without authentication, do the following (having installed xnest):

	Xnest -ac :1 &
metacity --display=:1.0 &
xclock --display=:1.0 &

The second line starts a window manager (always useful!). The third line starts a clock application so you can check it works (not necessary). Now set the DISPLAY variable to :1.0 in the same way as mentioned above, and you can debug inside your nested server.


5.    Disabling pointer grabs entirely
Allegedly, you can disable pointer grabs entirely by running with GDK_DEBUG=no_grabs in the environment. However, this only works if GTK+ is build with --enable-debug, and is untested here.
6.    Get your IDE to ungrab the pointer when it gets control
Your IDE should of course give you the option of fixing this by ungrabbing the pointer when a breakpoint is hit. I don't know any that do. It should be possible to put in a GDB hook to execute a small binary calling XUngrabPointer. I haven't tested it. It sounds harder than method 2.


Last Updated ( Monday, 22 October 2007 17:46 )