Intro To Mac Porting

From Apache OpenOffice Wiki
Jump to: navigation, search
Documentation caution.png This page is obsolete. Mac has been fully supported since OpenOffice 3.0. See Documentation/Building_Guide_AOO for current information.


Introduction To Porting OpenOffice.org To the Mac

The goal of this article is to teach any developer interested in joining the Macintosh porting team of OpenOffice.org the basic information to get started. After reading this guide the newcomer will understand: how to connect with other members of the team, how to get and compile the source code, the purpose and organization of the VCL module and finally how to use the Carbon API. This also summarizes the knowledge that I had to acquire to complete my Google Summer of Code 2006 project. I would like to thank the following people for helping me and teaching me what they knew: Eric Bachard and Pavel Janik.

Programming and System Requirements

Programming Requirements

To be comfortable in working on the porting project you should have a good knowledge of C++, a basic knowledge of the UNIX command line and if possible some knowledge of the Mac OS X Carbon API. The most important is that you need to be familiar with C++. The Carbon API can be learned very easily with the extensive documentation that Apple provides. Here are some important pages that you should get familiar with:

Carbon Guides

Carbon References

System Requirements

A Macintosh (PowerPC/Intel) running Mac OS X 10.4. You need to have XCode (need login to access old versions) installed. There are some problems with the latest versions, so download either 2.1 or 2.2. This will ensure that you have the proper tools installed to compile the source and will minimize the number of problems.

Connect With the OOo Developer Teams

IRC Channels

An important part of working on the OpenOffice.org project is to be connected with other developers to get and give help. Online chat channels are the first essential mean of communication between them. This is an important step. You will probably run into some problems when compiling the source code and you can find the answers by asking people in these rooms. Therefore download an IRC client such as Colloquy or X-Chat Aqua before going any further.

How to connect to these channels

Server

  • irc.freenode.net

Rooms

  • #dev.openoffice.org – main developer room.
  • #ooo_macport – room for the mac porting team, weekly meetings.
  • #openoffice.org – room for users.
  • #fr.openoffice.org – French developers room.
  • #openoffice.org-de – German developers room.


The first two are the most important rooms. If you are a developer from a non-English speaking country there is a good chance that you will also be able to find a room specific for OOo developers speaking your language. The last two, are examples of such rooms.

Create an account on OpenOffice.org

You need to create an account on OpenOffice.org. This account will allow you to manage, which projects you are a member of and to subscribe to mailing lists (next step). Also you will have access to IssueZilla and will be able to follow the evolution of issues by receiving forwarded emails about them. You will also be able to ask for the permission of committing source code later on.

Mailing Lists

Another essential part of being connected to the OOo community is to subscribe to mailing lists. This is where new code is sent for testing and where current issues are discussed. If you are stuck on something it is a very good idea to send your question to the mailing lists. A lot of people are subscribed to them and you will certainly find an answer. You can check all the mailing lists here. You should subscribe at least to the following ones:

  • dev@openoffice.org: general developers mailing list
  • mac@porting.openoffice.org: mac porting specific list
  • dev@gsl.openoffice.org: vcl specific list (more on vcl later)

Sign the JCA

An important step before submitting new code or fixing code is to sign the JCA. This is an agreement that gives Sun joint ownership over the code you wrote and want to include in the source. Go to this page and at the bottom you can find a link to the pdf version of the agreement and the terms. You have to sign and submit this agreement for your code to be included in the OOo source tree.

Compilation and tips

Information about downloading the source code can be found here:

Before starting the compilation, you should download ccache. This program is a caching pre-processor to C/C++ compilers. It will speed up the compilation process.

Here is a simple shell script to automate the compilation process. You need to replace the path to the source code with the proper path. Also you need to change the path to gcp in the ./configure options (Here the path assumes you are using 'DarwinPorts'). Finally you will need to change the source command if you are using an Intel machine to source MacOSXIntelEnv.Set.sh

[sh,N]

  1. ! /bin/sh

cd <path>680_m182/source/config_office

export CC="ccache gcc" export CXX="ccache g++"

./configure \ --without-nas \ --disable-odk \ --disable-cups \ --disable-gtk \ --disable-gnome-vfs \ --disable-crashdump \ --disable-mozilla \ --with-jdk-home=/System/Library/Frameworks/JavaVM.framework/Home \ --enable-pasf \ --enable-fontconfig \ --with-gnu-cp=/opt/local/bin/gcp \ --with-system-expat \ --with-system-curl \ --with-system-libxml

cd .. ./bootstrap source MacOSXPPCEnv.Set.sh dmake 2>&1 | tee log.log

You can now launch the compilation. Don't forget that if you run into some problems you can always ask on the IRC channels. Also since the compilation process takes some time, start introducing yourself to the other developers on the team, ask which parts need to be worked on and choose one that is interesting to you.

VCL

VCL Dependencies

VCL stands for 'Visual Class Library', it is the module responsible for linking the underlying functions of OOo to the graphical interface. It contains the implementation of all the components of the GUI for each platform. The folder of interest for us is the 'aqua' folder. This is where you will spend most of your time and once the aqua part of VCL has been implemented completely we will be able to run OOo without X11.

Structure of VCL

Structure of VCL


VCL Module

  • inc: contains all the header files of VCL.
  • prj: build.lst contains the dependencies of VCL for compilation and d.lst contains the files that will be sent back to the solver after the compilation of vcl is over.
  • qa: contains quality assurance tests for debugging.
  • source: contains the source files of the module. These files are platform independent.
  • test: contains small testing programs used to check specific parts of VCL. For example the drag and drop feature.
  • unx: contains the unix implementation for the GUI.
  • util: contains the makefiles used to build the module
  • win: contains the windows implementation for the GUI
  • workben: contains 'svdem', the application used to test the aqua implementation.

Aqua

  • app: contains all the native files related to the application as a whole
  • gdi: stands for Graphical Display Interface and contains all the files related to displaying bitmaps, geometric shapes, fonts etc...
  • src: contains the makefile of the aqua part.
  • window: contains all the files related to displaying the windows and menus.

Svdem in VCL

Svdem is a simple application that is used to test and show the evolution of the implementation of the aqua part of VCL. It is implemented like a regular OOo application and uses VCL the same way. Here is a picture of the 'svdem' application in VCL:

The svdem application in VCL

Svdem in svtools

Svtools is a module containing file/print dialogues, color chooser, font chooser, calendars etc... It uses VCL to display these elements so another svdem application has been created in this module so we can test the look of the elements it implements. Here is a screenshot:

The svdem application in svtools. Bigger Version

Carbon and VCL

Using Carbon in VCL is actually easier than it seems. You just need to first be comfortable with the concepts of Carbon and how to manipulate the different elements of the API and then it will be very easy to implement functions. I will show you an example of how to implement a VCL function with Carbon later, but now you need to understand how using Carbon was made possible in VCL.

Header files

As you should know by now, the Carbon API is included in a program by writing <Carbon/Carbon.h> in the source file. In VCL this is done in a couple files. The most important are:

.../inc/aquavclevents.hxx: contains the definition of all the Carbon event types that we want to handle in OOo. .../inc/aquavcltypes.h: redefines some Carbon types to avoid confusion.

Two other header files that you will see being included quite often are source/solenv/inc/premac.h and source/solenv/inc/postmac.h. The sole purpose of these files is to redefine some mac primitive types to avoid conflicts with other parts of the code. This is currently a hack and will most likely be removed and implemented differently in the future.

Example of using Carbon in VCL

The procedure to follow when looking at implementing a function in any part of VCL is to look at the corresponding Windows implementation in the vcl/win folder. The Windows API is actually very close to the Carbon API and the Windows implementation can always give you an idea about how to structure your function. Here I am taking the example of the ShowFullScreen function in salframe.cxx. Here is the code in win/window/salframe.cxx:

[cpp,N] void WinSalFrame::ShowFullScreen( BOOL bFullScreen ) {

   if ( mbFullScreen == bFullScreen )
       return;
   mbFullScreen = bFullScreen;
   if ( bFullScreen )
   {
       // Damit Taskleiste von Windows ausgeblendet wird
       DWORD nExStyle = GetWindowExStyle( mhWnd );
       if ( nExStyle & WS_EX_TOOLWINDOW )
       {
           mbFullScreenToolWin = TRUE;
           nExStyle &= ~WS_EX_TOOLWINDOW;
           SetWindowExStyle( mhWnd, nExStyle );
       }
       // save old position
       GetWindowRect( mhWnd, &maFullScreenRect );
       // save show state
       mnFullScreenShowState = mnShowState;
       if ( !(GetWindowStyle( mhWnd ) & WS_VISIBLE) )
           mnShowState = SW_SHOW;
       // set window to screen size
       ImplSalFrameFullScreenPos( this, TRUE );
   }
   else
   {
       // Do the opposite

...

   }

}

For the sake of space I did not include the code of the else statement. The first thing you need to look at are the arguments passed to the function. Here a boolean bFullScreen. You should read the OOo code guidelines that describe the use of lowercase letters in front of variables. This argument will actually tell the function if we want to go in fullscreen mode when true and exit fullscreen mode when false. By reading the code above, we can deduce the following structure to our function:

  • check if the mode wanted equals the mode we are currently in.
  • if we want to go into fullscreen mode, save the current state of the window, compute display bounds and resize window.
  • If we want to exit fullscreen mode, put window into old state and resize.

The first thing to do is look in the Carbon API how to get the current display's size, how to resize a window and how to save the current state of a window.

Display size

To get the current display size you need to look in the Quartz Display Reference and look at the 'Functions by Task' tab. Most of the time you will be able to find what you need in there. The fourth section is interesting here since it talks about getting the display's configuration. Then in the list of functions under this category you can find the CGDisplayScreenSize function. This function takes the display ID as an argument, which makes sense since you might have multiple displays connected together. The description of the type of the argument gives you a clue about finding the displays ID. You need to use the MainDisplayID function. As you can see it is very important that you define the structure of your function properly since it will make your search in the Carbon API much easier.

Resize window

To implement this part you need to look at the Window Manager Reference. Again you should follow the same process to look for the proper functions to use. One important thing when you have to save the current state and attributes of the window is where to save them. You have to save them in the AquaSalFrame class itself. Once again if you look at the Windows implementation, you can find in vcl/win/inc/salframe.h that the size of the window is saved in the maFullScreenRect variable. Therefore it is advised that you use the same identifiers to avoid confusion. The attributes also need to be saved. In this case Windows does it differently but Carbon can save all the attributes in one variable. So we will create a WindowAttributes variable and give it the name maFullScreenAttr. Now we are able to finish implementing the function. Here is how the final code looks like:

[cpp,N] void AquaSalFrame::ShowFullScreen( BOOL bFullScreen ) {

   fprintf(stderr, ">*>_> %s\n",__func__);

if( mbFullScreen == bFullScreen ) return;

mbFullScreen = bFullScreen; AquaSalFrame* pFrame = this; if( bFullScreen ) { Rect newBounds; ImplSalCalcFullScreenSize( pFrame, &newBounds ); // Get new bounds GetWindowAttributes( mrWindow, &maFullScreenAttr ); // Save attributes ChangeWindowAttributes( mrWindow, kWindowNoAttributes, maFullScreenAttr ); GetWindowBounds( mrWindow, kWindowContentRgn, &maFullScreenRect ); SetWindowBounds( mrWindow, kWindowContentRgn, &newBounds ); SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar ); // -> Shows menubar when we move the mouse over it. } else { SetWindowBounds( mrWindow, kWindowContentRgn, &maFullScreenRect ); ChangeWindowAttributes( mrWindow, maFullScreenAttr, kWindowNoAttributes ); SetSystemUIMode( kUIModeNormal, nil ); } }

static void ImplSalCalcFullScreenSize( const AquaSalFrame* pFrame, Rect* pSize ) { CGDirectDisplayID mainDisplayID = CGMainDisplayID(); printf("Display ID %d\n", mainDisplayID);

CGRect rect; rect = CGDisplayBounds( mainDisplayID ); printf( "Screen resolution: %fx%f\n", rect.size.width, rect.size.height );

// Stores current resolution in pSize. // Rect made out of ints -> cast required -> CGRect made out of floats. pSize->top = 0; pSize->left = 0; pSize->bottom = static_cast<int>(rect.size.height); pSize->right = static_cast<int>(rect.size.width); }

Testing with svdem

Since AquaSalFrame is implementation dependent. The programs of OpenOffice.org do not access this class directly but by using Wrapper functions. If you open vcl/workben/svdem.cxx you can see that the class MyWin used to display the window of svdem is a descendant of WorkWindow. WorkWindow is therefore the class you need to look at to see how you can invoke the fullscreen function properly. You can find it in vcl/source/window/wrkwin.cxx. In this file you have the ShowFullScreenMode function. This is the function you need to use. To test what was implemented is just the matter of calling: aMainWin.ShowFullScreenMode(true) in svdem. You need to use a similar process for all the new functions you implement.

Conclusion

To conclude this brief introduction, I would advise you to first get connected to the team so you know where you can contribute and choose something that is interesting for you also. After that I would advise you to get the source code, compile it and run svdem to see how everything works. After that you can start working on the code. Until VCL is replaced with a more modern toolkit, the strategy to successfully implement new features is to understand how VCL implements them by looking at the Windows implementation and then understand how Carbon would implement it and combine both to make it happen.

-- Pdefilippis aliscafo@gmail.com

Personal tools