Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / widget / src / photon / nsWindow.cpp
blob50aa486f9edd21a8f69e90329a5bc5545d3cfa2f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Jerry.Kirk@Nexwarecorp.com
24 * Dale.Stansberry@Nexwarecorop.com
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 #include <Pt.h>
42 #include <photon/PtServer.h>
43 #include "PtRawDrawContainer.h"
44 #include "nsCRT.h"
46 #include "nsWindow.h"
47 #include "nsWidgetsCID.h"
48 #include "nsIFontMetrics.h"
49 #include "nsFont.h"
50 #include "nsGUIEvent.h"
51 #include "nsIRenderingContext.h"
52 #include "nsIRegion.h"
53 #include "nsRect.h"
54 #include "nsTransform2D.h"
55 #include "nsGfxCIID.h"
56 #include "nsToolkit.h"
57 #include "nsIPrefBranch.h"
58 #include "nsIPrefService.h"
60 #include "nsClipboard.h"
61 #include "nsIRollupListener.h"
63 #include "nsIServiceManager.h"
64 #include "nsIAppShell.h"
65 #include "nsIDocShell.h"
67 #include "nsIViewManager.h"
68 #include "nsIXULWindow.h"
69 #include "nsIDocShellTreeItem.h"
70 #include "nsIWindowMediator.h"
71 #include "nsIPresShell.h"
72 #include "nsReadableUtils.h"
74 static PhTile_t *GetWindowClipping( PtWidget_t *aWidget );
76 nsIRollupListener *nsWindow::gRollupListener = nsnull;
77 nsIWidget *nsWindow::gRollupWidget = nsnull;
78 static PtWidget_t *gMenuRegion;
80 /* avoid making a costly PhWindowQueryVisible call */
81 static PhRect_t gConsoleRect;
82 static PRBool gConsoleRectValid = PR_FALSE;
83 #define QueryVisible( ) {\
84 if( gConsoleRectValid == PR_FALSE ) { \
85 PhWindowQueryVisible( Ph_QUERY_IG_POINTER, 0, 1, &gConsoleRect ); \
86 gConsoleRectValid = PR_TRUE;\
87 } \
90 //-------------------------------------------------------------------------
92 // nsWindow constructor
94 //-------------------------------------------------------------------------
95 nsWindow::nsWindow()
97 mClientWidget = nsnull;
98 mIsTooSmall = PR_FALSE;
99 mBorderStyle = eBorderStyle_default;
100 mWindowType = eWindowType_child;
101 mLastMenu = nsnull;
104 //-------------------------------------------------------------------------
106 // nsWindow destructor
108 //-------------------------------------------------------------------------
109 nsWindow::~nsWindow()
111 nsWindow *p = (nsWindow*)mParent;
112 if( p && p->mLastMenu == mWidget ) p->mLastMenu = nsnull;
114 // always call destroy. if it's already been called, there's no harm
115 // since it keeps track of when it's already been called.
116 Destroy();
119 PRBool nsWindow::IsChild() const
121 return PR_FALSE;
124 NS_IMETHODIMP nsWindow::WidgetToScreen( const nsRect& aOldRect, nsRect& aNewRect ) {
126 PhPoint_t pos, offset;
127 PtWidget_t *disjoint = PtFindDisjoint( mWidget );
129 QueryVisible( );
131 PtGetAbsPosition( disjoint, &pos.x, &pos.y );
132 PtWidgetOffset( mWidget, &offset );
133 aNewRect.x = pos.x + offset.x + aOldRect.x - gConsoleRect.ul.x;
134 aNewRect.y = pos.y + offset.y + aOldRect.y - gConsoleRect.ul.y;
136 aNewRect.width = aOldRect.width;
137 aNewRect.height = aOldRect.height;
139 return NS_OK;
142 void nsWindow::DestroyNative(void)
144 if ( mClientWidget )
146 PtDestroyWidget(mClientWidget );
147 mClientWidget = nsnull;
149 // destroy all of the children that are nsWindow() classes
150 // preempting the gdk destroy system.
151 if( mWidget ) DestroyNativeChildren();
153 // Call the base class to actually PtDestroy mWidget.
154 nsWidget::DestroyNative();
157 // this function will walk the list of children and destroy them.
158 // the reason why this is here is that because of the superwin code
159 // it's very likely that we will never get notification of the
160 // the destruction of the child windows. so, we have to beat the
161 // layout engine to the punch. CB
163 void nsWindow::DestroyNativeChildren(void)
165 for(PtWidget_t *w=PtWidgetChildFront( mWidget ); w; w=PtWidgetBrotherBehind( w ))
167 if( w->flags & Pt_DESTROYED ) continue;
168 nsWindow *childWindow = static_cast<nsWindow *>(GetInstance(w));
169 if( childWindow && !childWindow->mIsDestroying) childWindow->Destroy();
173 NS_IMETHODIMP nsWindow::CaptureRollupEvents( nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent ) {
174 PtWidget_t *grabWidget;
175 grabWidget = mWidget;
177 if (aDoCapture) {
178 NS_IF_RELEASE(gRollupListener);
179 NS_IF_RELEASE(gRollupWidget);
180 gRollupListener = aListener;
181 NS_ADDREF(aListener);
182 gRollupWidget = this;
183 NS_ADDREF(this);
185 /* Realize the gMenuRegion to capture events outside of the application's canvas when menus are displayed */
186 /* Menus+submenus have the same parent. If the parent has mLastMenu set and realized, then use its region as "infront" */
187 /* If not, then this widget ( mWidget ) becomes the mLastMenu and gets recorded into the parent */
188 /* Different windows have different mLastMenu's */
189 if( mWindowType == eWindowType_popup && !( PtWidgetFlags( gMenuRegion ) & Pt_REALIZED ) && mParent ) {
191 PtWidget_t *pw = ((nsWindow*)mParent)->mLastMenu;
193 if( pw && ( PtWidgetFlags( pw ) & Pt_REALIZED ) && PtWidgetRid( pw ) > 0 )
194 PtSetResource( gMenuRegion, Pt_ARG_REGION_INFRONT, PtWidgetRid( pw ), 0 );
195 else {
196 if( !PtWidgetIsRealized( mWidget ) ) PtRealizeWidget( mWidget );
197 PtSetResource( gMenuRegion, Pt_ARG_REGION_INFRONT, PtWidgetRid( mWidget ), 0 );
198 ((nsWindow*)mParent)->mLastMenu = mWidget;
201 PtRealizeWidget( gMenuRegion );
204 else {
205 NS_IF_RELEASE(gRollupListener);
206 gRollupListener = nsnull;
207 NS_IF_RELEASE(gRollupWidget);
208 gRollupWidget = nsnull;
210 if( mWindowType == eWindowType_popup && ( PtWidgetFlags( gMenuRegion ) & Pt_REALIZED ) )
211 PtUnrealizeWidget( gMenuRegion );
214 return NS_OK;
217 NS_METHOD nsWindow::PreCreateWidget( nsWidgetInitData *aInitData ) {
218 if (nsnull != aInitData) {
219 SetWindowType( aInitData->mWindowType );
220 SetBorderStyle( aInitData->mBorderStyle );
221 return NS_OK;
223 return NS_ERROR_FAILURE;
227 //-------------------------------------------------------------------------
229 // Create the native widget
231 //-------------------------------------------------------------------------
232 NS_METHOD nsWindow::CreateNative( PtWidget_t *parentWidget ) {
233 PtArg_t arg[25];
234 int arg_count = 0;
235 PhPoint_t pos;
236 PhDim_t dim;
237 unsigned long render_flags;
238 nsresult result = NS_ERROR_FAILURE;
240 pos.x = mBounds.x;
241 pos.y = mBounds.y;
242 dim.w = mBounds.width;
243 dim.h = mBounds.height;
245 switch( mWindowType )
247 case eWindowType_popup :
248 mIsToplevel = PR_TRUE;
249 break;
250 case eWindowType_toplevel :
251 case eWindowType_invisible :
252 mIsToplevel = PR_TRUE;
253 break;
254 case eWindowType_dialog :
255 mIsToplevel = PR_TRUE;
256 break;
257 case eWindowType_child :
258 mIsToplevel = PR_FALSE;
259 break;
262 if ( mWindowType == eWindowType_child )
264 arg_count = 0;
265 PtSetArg( &arg[arg_count++], Pt_ARG_POS, &pos, 0 );
266 PtSetArg( &arg[arg_count++], Pt_ARG_DIM, &dim, 0 );
267 PtSetArg( &arg[arg_count++], Pt_ARG_RESIZE_FLAGS, 0, Pt_RESIZE_XY_BITS );
268 PtSetArg( &arg[arg_count++], Pt_ARG_FLAGS, 0 , Pt_HIGHLIGHTED|Pt_GETS_FOCUS );
269 PtSetArg( &arg[arg_count++], Pt_ARG_BORDER_WIDTH, 0, 0 );
270 PtSetArg( &arg[arg_count++], Pt_ARG_FILL_COLOR, Pg_RED, 0 );
271 PtSetArg( &arg[arg_count++], RDC_DRAW_FUNC, RawDrawFunc, 0 );
272 mWidget = PtCreateWidget( PtRawDrawContainer, parentWidget, arg_count, arg );
274 else
276 // No border or decorations is the default
277 render_flags = 0; // Ph_WM_RENDER_RESIZE;
279 if( mWindowType != eWindowType_popup ) {
281 #define PH_BORDER_STYLE_ALL \
282 Ph_WM_RENDER_TITLE | \
283 Ph_WM_RENDER_CLOSE | \
284 Ph_WM_RENDER_BORDER | \
285 Ph_WM_RENDER_RESIZE | \
286 Ph_WM_RENDER_MAX | \
287 Ph_WM_RENDER_MIN | \
288 Ph_WM_RENDER_MENU
291 if( mBorderStyle & eBorderStyle_all ) render_flags |= PH_BORDER_STYLE_ALL;
292 else
294 if( mBorderStyle & eBorderStyle_border ) render_flags |= Ph_WM_RENDER_BORDER;
295 if( mBorderStyle & eBorderStyle_title ) render_flags |= ( Ph_WM_RENDER_TITLE | Ph_WM_RENDER_BORDER );
296 if( mBorderStyle & eBorderStyle_close ) render_flags |= Ph_WM_RENDER_CLOSE;
297 if( mBorderStyle & eBorderStyle_menu ) render_flags |= Ph_WM_RENDER_MENU;
298 if( mBorderStyle & eBorderStyle_resizeh ) render_flags |= Ph_WM_RENDER_RESIZE;
299 if( mBorderStyle & eBorderStyle_minimize ) render_flags |= Ph_WM_RENDER_MIN;
300 if( mBorderStyle & eBorderStyle_maximize ) render_flags |= Ph_WM_RENDER_MAX;
303 arg_count = 0;
304 if (mWindowType == eWindowType_dialog)
306 // center on parent
307 if (parentWidget)
309 PtCalcAbsPosition(parentWidget, NULL, &dim, &pos);
310 PtSetArg( &arg[arg_count++], Pt_ARG_POS, &pos, 0 );
313 else if ((mWindowType == eWindowType_toplevel) && parentWidget)
315 QueryVisible( );
316 pos.x += gConsoleRect.ul.x;
317 pos.y += gConsoleRect.ul.y;
318 PtSetArg( &arg[arg_count++], Pt_ARG_POS, &pos, 0 );
321 PtSetArg( &arg[arg_count++], Pt_ARG_DIM, &dim, 0 );
322 PtSetArg( &arg[arg_count++], Pt_ARG_RESIZE_FLAGS, 0, Pt_RESIZE_XY_BITS );
324 /* Create Pop-up Menus as a PtRegion */
326 if (!parentWidget)
327 PtSetParentWidget( nsnull );
329 if( mWindowType == eWindowType_popup ) {
331 /* the gMenuRegion is used to capture events outside of the application's canvas when menus are displayed */
332 if( !gMenuRegion ) {
333 PtArg_t args[10];
334 PtSetParentWidget( NULL );
335 PtSetArg( &args[0], Pt_ARG_REGION_PARENT, 0, 0 );
336 PtSetArg( &args[1], Pt_ARG_FILL_COLOR, Pg_TRANSPARENT, 0);
337 PhArea_t area = { { 0, 0 }, { SHRT_MAX, SHRT_MAX } };
338 PtSetArg( &args[2], Pt_ARG_AREA, &area, 0 );
339 PtSetArg( &args[3], Pt_ARG_REGION_SENSE, Ph_EV_BUT_PRESS, Ph_EV_BUT_PRESS );
340 PtSetArg( &args[4], Pt_ARG_REGION_FLAGS, Ph_FORCE_BOUNDARY, Ph_FORCE_BOUNDARY );
341 PtSetArg( &args[5], Pt_ARG_CURSOR_TYPE, Ph_CURSOR_POINTER, 0 );
342 gMenuRegion = PtCreateWidget( PtRegion, NULL, 6, args );
343 PtAddEventHandler( gMenuRegion, Ph_EV_BUT_PRESS, MenuRegionCallback, this );
346 int fields = Ph_REGION_PARENT|Ph_REGION_HANDLE| Ph_REGION_FLAGS|Ph_REGION_ORIGIN|Ph_REGION_EV_SENSE|Ph_REGION_EV_OPAQUE|Ph_REGION_RECT;
347 int sense = Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE | Ph_EV_BUT_REPEAT;
348 PtCallback_t cb_destroyed = { MenuRegionDestroyed, NULL };
350 PtSetArg( &arg[arg_count++], Pt_ARG_REGION_FIELDS, fields, fields );
351 PtSetArg( &arg[arg_count++], Pt_ARG_REGION_PARENT, Ph_ROOT_RID, 0 );
352 PtSetArg( &arg[arg_count++], Pt_ARG_REGION_SENSE, sense | Ph_EV_DRAG|Ph_EV_EXPOSE, sense | Ph_EV_DRAG|Ph_EV_EXPOSE);
353 PtSetArg( &arg[arg_count++], Pt_ARG_REGION_OPAQUE, sense | Ph_EV_DRAG|Ph_EV_EXPOSE|Ph_EV_DRAW|Ph_EV_BLIT, sense |Ph_EV_DRAG|Ph_EV_EXPOSE|Ph_EV_DRAW|Ph_EV_BLIT);
354 PtSetArg( &arg[arg_count++], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, Pt_GETS_FOCUS | Pt_DELAY_REALIZE);
355 PtSetArg( &arg[arg_count++], Pt_CB_DESTROYED, &cb_destroyed, 0 );
356 mWidget = PtCreateWidget( PtRegion, parentWidget, arg_count, arg);
358 // Must also create the client-area widget
359 arg_count = 0;
360 PtSetArg( &arg[arg_count++], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_ALL, ~0 );
361 PtSetArg( &arg[arg_count++], Pt_ARG_BORDER_WIDTH, 0 , 0 );
362 PtSetArg( &arg[arg_count++], Pt_ARG_MARGIN_WIDTH, 0 , 0 );
363 PhRect_t anch_offset = {{0, 0},{0, 0}};
364 PtSetArg( &arg[arg_count++], Pt_ARG_ANCHOR_OFFSETS, &anch_offset, 0 );
366 PtSetArg( &arg[arg_count++], RDC_DRAW_FUNC, RawDrawFunc, 0 );
367 PtSetArg( &arg[arg_count++], Pt_ARG_FLAGS, 0, (Pt_HIGHLIGHTED | Pt_GETS_FOCUS));
368 mClientWidget = PtCreateWidget( PtRawDrawContainer, mWidget, arg_count, arg );
370 else {
371 /* Dialog and TopLevel Windows */
372 PtSetArg( &arg[arg_count++], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, Pt_DELAY_REALIZE);
373 PtSetArg( &arg[arg_count++], Pt_ARG_WINDOW_RENDER_FLAGS, render_flags, -1 );
374 PtSetArg( &arg[arg_count++], Pt_ARG_WINDOW_MANAGED_FLAGS, 0, Ph_WM_CLOSE );
375 PtSetArg( &arg[arg_count++], Pt_ARG_WINDOW_NOTIFY_FLAGS, Ph_WM_CLOSE|Ph_WM_CONSWITCH|Ph_WM_FOCUS, ~0 );
376 PtSetArg( &arg[arg_count++], Pt_ARG_FILL_COLOR, Pg_TRANSPARENT, 0 );
378 PtRawCallback_t cb_raw = { Ph_EV_INFO, EvInfo, NULL };
379 PtCallback_t cb_resize = { ResizeHandler, NULL };
380 PtCallback_t cb_window = { WindowWMHandler, this };
382 PtSetArg( &arg[arg_count++], Pt_CB_RESIZE, &cb_resize, NULL );
383 PtSetArg( &arg[arg_count++], Pt_CB_RAW, &cb_raw, NULL );
384 PtSetArg( &arg[arg_count++], Pt_CB_WINDOW, &cb_window, 0 );
385 mWidget = PtCreateWidget( PtWindow, parentWidget, arg_count, arg );
389 if( mWidget ) {
390 SetInstance( mWidget, this );
391 if( mClientWidget ) SetInstance( mClientWidget, this );
392 if( mWindowType == eWindowType_child ) {
393 PtAddCallback(mWidget, Pt_CB_RESIZE, ResizeHandler, nsnull );
394 PtAddEventHandler( mWidget,
395 Ph_EV_PTR_MOTION_BUTTON | Ph_EV_PTR_MOTION_NOBUTTON |
396 Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE |Ph_EV_BOUNDARY|Ph_EV_DRAG
397 , RawEventHandler, this );
399 PtArg_t arg;
400 PtRawCallback_t callback;
402 callback.event_mask = ( Ph_EV_KEY ) ;
403 callback.event_f = RawEventHandler;
404 callback.data = this;
405 PtSetArg( &arg, Pt_CB_FILTER, &callback, 0 );
406 PtSetResources( mWidget, 1, &arg );
408 else if( mWindowType == eWindowType_popup ) {
409 PtAddEventHandler( mClientWidget,
410 Ph_EV_PTR_MOTION_BUTTON | Ph_EV_PTR_MOTION_NOBUTTON |
411 Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE |Ph_EV_BOUNDARY,
412 RawEventHandler, this );
414 PtAddEventHandler( mWidget, Ph_EV_DRAG, RawEventHandler, this );
416 PtArg_t arg;
417 PtRawCallback_t callback;
419 callback.event_mask = ( Ph_EV_KEY ) ;
420 callback.event_f = RawEventHandler;
421 callback.data = this;
422 PtSetArg( &arg, Pt_CB_FILTER, &callback, 0 );
423 PtSetResources( mClientWidget, 1, &arg );
425 PtAddCallback(mClientWidget, Pt_CB_RESIZE, ResizeHandler, nsnull );
427 else if( !parentWidget ) {
428 if( mClientWidget ) PtAddCallback(mClientWidget, Pt_CB_RESIZE, ResizeHandler, nsnull );
431 // call the event callback to notify about creation
432 DispatchStandardEvent( NS_CREATE );
434 result = NS_OK;
437 /* force SetCursor to actually set the cursor, even though our internal state indicates that we already
438 have the standard cursor */
439 mCursor = eCursor_wait;
440 SetCursor( mCursor );
442 return result;
446 //-------------------------------------------------------------------------
448 // Return some native data according to aDataType
450 //-------------------------------------------------------------------------
451 void *nsWindow::GetNativeData(PRUint32 aDataType)
453 switch(aDataType)
455 case NS_NATIVE_WINDOW:
456 if( !mWidget ) return (void *)mWidget;
458 case NS_NATIVE_WIDGET:
459 if (mClientWidget) return (void *) mClientWidget;
460 else return (void *) mWidget;
463 return nsWidget::GetNativeData(aDataType);
466 //-------------------------------------------------------------------------
468 // Scroll the bits of a window
470 //-------------------------------------------------------------------------
471 NS_METHOD nsWindow::Scroll( PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect ) {
472 PtWidget_t *widget = (PtWidget_t *)GetNativeData(NS_NATIVE_WIDGET);
474 /* If aDx and aDy are 0 then skip it or if widget == null */
475 if( ( !aDx && !aDy ) || (!widget )) return NS_OK;
477 PtStartFlux( widget );
479 PtWidget_t *w;
480 for( w=PtWidgetChildFront( widget ); w; w=PtWidgetBrotherBehind( w )) {
481 PtArg_t arg;
482 PhPoint_t p;
483 p.x = w->area.pos.x + aDx;
484 p.y = w->area.pos.y + aDy;
486 PtSetArg( &arg, Pt_ARG_POS, &p, 0 );
487 PtSetResources( w, 1, &arg ) ;
489 nsWindow *pWin = (nsWindow *) GetInstance(w);
490 if (pWin) {
491 pWin->mBounds.x += aDx;
492 pWin->mBounds.y += aDy;
496 PtEndFlux( widget);
498 PhRect_t source = {{widget->area.pos.x, widget->area.pos.y},{widget->area.pos.x+ widget->area.size.w-1, widget->area.pos.y + widget->area.size.h-1}};
499 PhPoint_t point = { aDx, aDy };
501 if( !widget->damage_list )
502 PtBlit( widget, &source, &point );
503 else {
504 /* first noticed as a scrolling problem in netscape email */
505 /* the scrolling should be clipped out by the rectangles given by Invalidate(). These are accumulated in widget->damage_list */
506 PhTile_t original = { source, NULL }, *clip;
508 clip = PhGetTile();
509 clip->rect = source;
510 clip->next = NULL;
511 clip = PhClipTilings( clip, widget->damage_list, NULL );
513 if( clip ) {
514 PtClippedBlit( widget, &original, &point, clip );
515 PhFreeTiles( clip );
519 return NS_OK;
522 NS_METHOD nsWindow::ScrollWidgets( PRInt32 aDx, PRInt32 aDy ) {
523 PtWidget_t *widget = (PtWidget_t *)GetNativeData(NS_NATIVE_WIDGET);
525 if( ( !aDx && !aDy ) || (!widget )) return NS_OK;
527 PtStartFlux( widget );
529 PtWidget_t *w;
530 for( w=PtWidgetChildFront( widget ); w; w=PtWidgetBrotherBehind( w )) {
531 PtArg_t arg;
532 PhPoint_t p;
533 p.x = w->area.pos.x + aDx;
534 p.y = w->area.pos.y + aDy;
535 PtSetArg( &arg, Pt_ARG_POS, &p, 0 );
536 PtSetResources( w, 1, &arg ) ;
538 nsWindow *pWin = (nsWindow *) GetInstance(w);
539 if (pWin) {
540 pWin->mBounds.x += aDx;
541 pWin->mBounds.y += aDy;
545 PtEndFlux( widget);
546 return NS_OK;
549 NS_METHOD nsWindow::SetTitle( const nsAString& aTitle ) {
550 if( mWidget ) {
551 char * title = ToNewUTF8String(aTitle);
552 PtSetResource( mWidget, Pt_ARG_WINDOW_TITLE, title, 0 );
553 if (title) nsCRT::free(title);
555 return NS_OK;
559 NS_IMETHODIMP nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
561 PRBool nNeedToShow = PR_FALSE;
563 if( aWidth == mBounds.width && aHeight == mBounds.height ) return NS_OK;
565 mBounds.width = aWidth;
566 mBounds.height = aHeight;
568 // code to keep the window from showing before it has been moved or resized
569 // if we are resized to 1x1 or less, we will hide the window. Show(TRUE) will be ignored until a larger resize has happened
570 if( aWidth <= 1 || aHeight <= 1 ) {
571 aWidth = aHeight = 1;
572 mIsTooSmall = PR_TRUE;
574 else {
575 if( mIsTooSmall ) {
576 // if we are not shown, we don't want to force a show here, so check and see if Show(TRUE) has been called
577 nNeedToShow = mShown;
578 mIsTooSmall = PR_FALSE;
582 PhDim_t dim = { aWidth, aHeight };
584 if( mWidget ) {
585 // center the dialog
586 if( mWindowType == eWindowType_dialog ) {
587 PhPoint_t p;
588 QueryVisible( );
589 PtCalcAbsPosition( NULL, NULL, &dim, &p );
590 p.x -= gConsoleRect.ul.x;
591 p.y -= gConsoleRect.ul.y;
592 Move(p.x, p.y); // the move should be in coordinates assuming the console is 0, 0
594 if( aRepaint == PR_FALSE ) PtStartFlux(mWidget);
595 PtSetResource( mWidget, Pt_ARG_DIM, &dim, 0 );
596 if( aRepaint == PR_FALSE ) PtEndFlux(mWidget);
598 /* ATENTIE Remove when wojtek fixes PR:22930 in the photon library */
599 if( PtWidgetClass( mWidget ) == PtRegion ) PtSetResource( mWidget, Pt_ARG_REGION_OPAQUE, 0, Ph_EV_KEY );
602 if( mIsToplevel || mListenForResizes ) {
603 nsSizeEvent sevent(PR_TRUE, 0, nsnull);
604 sevent.message = NS_SIZE;
605 sevent.widget = this;
607 sevent.windowSize = new nsRect (0, 0, aWidth, aHeight);
609 sevent.refPoint.x = 0;
610 sevent.refPoint.y = 0;
611 sevent.mWinWidth = aWidth;
612 sevent.mWinHeight = aHeight;
613 // XXX fix this
614 sevent.time = 0;
615 AddRef();
616 DispatchWindowEvent(&sevent);
617 Release();
618 delete sevent.windowSize;
620 if( nNeedToShow ) Show(PR_TRUE);
621 return NS_OK;
624 int nsWindow::WindowWMHandler( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo )
626 PhWindowEvent_t *we = (PhWindowEvent_t *) cbinfo->cbdata;
627 switch( we->event_f ) {
628 case Ph_WM_CLOSE:
630 nsWindow * win = (nsWindow*) data;
631 NS_ADDREF(win);
633 // dispatch an "onclose" event. to delete immediately, call win->Destroy()
634 nsGUIEvent event(PR_TRUE, 0, nsnull);
635 nsEventStatus status;
637 event.message = NS_XUL_CLOSE;
638 event.widget = win;
640 event.time = 0;
641 event.refPoint.x = 0;
642 event.refPoint.y = 0;
644 win->DispatchEvent(&event, status);
646 NS_RELEASE(win);
648 break;
650 case Ph_WM_CONSWITCH:
651 gConsoleRectValid = PR_FALSE; /* force a call tp PhWindowQueryVisible() next time, since we might have moved this window into a different console */
652 /* rollup the menus */
653 if( gRollupWidget && gRollupListener ) gRollupListener->Rollup(nsnull);
654 break;
656 case Ph_WM_FOCUS:
657 if( we->event_state == Ph_WM_EVSTATE_FOCUSLOST ) {
658 /* rollup the menus */
659 if( gRollupWidget && gRollupListener ) gRollupListener->Rollup(nsnull);
661 if( sFocusWidget ) sFocusWidget->DispatchStandardEvent(NS_DEACTIVATE);
663 break;
666 return Pt_CONTINUE;
669 void nsWindow::RawDrawFunc( PtWidget_t * pWidget, PhTile_t * damage )
671 nsWindow * pWin = (nsWindow*) GetInstance( pWidget );
672 nsresult result;
673 PhTile_t * dmg = NULL;
674 nsPaintEvent pev(PR_TRUE, 0, nsnull);
675 PhRect_t extent;
677 if( !pWin || !pWin->mContext ) return;
679 if ( pWin->mEventCallback ) {
680 PhPoint_t offset;
681 nsRect nsDmg;
683 // Ok... The damage rect is in window coordinates and is not neccessarily clipped to
684 // the widgets canvas. Mozilla wants the paint coords relative to the parent widget, not the window.
685 PtWidgetExtent(pWidget, &extent);
686 PtWidgetOffset(pWidget, &offset);
687 /* Build a List of Tiles that might be in front of me.... */
688 PhTile_t *new_damage, *clip_tiles, *intersect;
689 /* Intersect the Damage tile list w/ the clipped out list and see what's left! */
690 new_damage = PhRectsToTiles(&damage->rect, 1);
691 PhDeTranslateTiles(new_damage, &offset);
692 clip_tiles = GetWindowClipping( pWidget );
693 if (clip_tiles) {
694 new_damage = PhClipTilings( new_damage, clip_tiles, NULL);
695 PhFreeTiles(clip_tiles);
697 clip_tiles = PhRectsToTiles(&extent, 1);
698 intersect = PhIntersectTilings( new_damage, clip_tiles, NULL);
699 if ( intersect == NULL ) return;
700 PhDeTranslateTiles(intersect, &extent.ul);
701 PhFreeTiles(clip_tiles);
702 PhFreeTiles(new_damage);
703 new_damage = intersect;
705 pWin->InitEvent(pev, NS_PAINT);
706 pev.region = nsnull;
707 pev.renderingContext = nsnull;
708 pev.renderingContext = pWin->GetRenderingContext();
709 for( dmg = new_damage; dmg; dmg = dmg->next ) {
710 nsDmg.x = dmg->rect.ul.x;
711 nsDmg.y = dmg->rect.ul.y;
712 nsDmg.width = dmg->rect.lr.x - dmg->rect.ul.x + 1;
713 nsDmg.height = dmg->rect.lr.y - dmg->rect.ul.y + 1;
715 if( (nsDmg.width <= 0 ) || (nsDmg.height <= 0 ) ) /* Move to the next Damage Tile */
716 continue;
718 /* Re-Setup Paint Event */
719 pWin->InitEvent(pev, NS_PAINT);
720 pev.refPoint.x = nsDmg.x;
721 pev.refPoint.y = nsDmg.y;
722 pev.rect = &nsDmg;
723 pev.region = nsnull;
725 if( pev.renderingContext ) {
726 nsIRegion *ClipRegion = pWin->GetRegion( );
727 ClipRegion->SetTo( nsDmg.x, nsDmg.y, nsDmg.width, nsDmg.height );
728 pev.renderingContext->SetClipRegion( static_cast<const nsIRegion &>(*(ClipRegion)), nsClipCombine_kReplace );
730 NS_RELEASE( ClipRegion );
732 /* You can turn off most drawing if you take this out */
733 result = pWin->DispatchWindowEvent(&pev);
736 NS_RELEASE(pev.renderingContext);
737 PhFreeTiles( new_damage );
741 static PhTile_t *GetWindowClipping( PtWidget_t *aWidget ) {
742 PtWidget_t *w;
743 PhTile_t *clip_tiles = NULL, *last = NULL;
744 PhRect_t w_extent;
746 PtWidgetExtent( aWidget, &w_extent);
748 for( w = PtWidgetChildFront( aWidget ); w; w=PtWidgetBrotherBehind( w ) ) {
749 long flags = PtWidgetFlags( w );
750 if( (flags & Pt_REALIZED) && (flags & Pt_OPAQUE) && !PtIsDisjoint(w) ) {
751 PhTile_t *tile = PhGetTile( );
752 if( !tile ) return NULL;
754 tile->rect.ul.x = w->area.pos.x + w_extent.ul.x;
755 tile->rect.ul.y = w->area.pos.y + w_extent.ul.y;
756 tile->rect.lr.x = tile->rect.ul.x + w->area.size.w - 1;
757 tile->rect.lr.y = tile->rect.ul.y + w->area.size.h - 1;
759 tile->next = NULL;
760 if( !clip_tiles ) clip_tiles = tile;
761 if( last ) last->next = tile;
762 last = tile;
765 return clip_tiles;
768 int nsWindow::ResizeHandler( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo )
770 nsWindow *someWindow = (nsWindow *) GetInstance(widget);
771 if( someWindow ) {
772 PtContainerCallback_t *cb = (PtContainerCallback_t *) cbinfo->cbdata;
773 PhRect_t *extents = &cb->new_size;
774 nsRect rect;
775 rect.x = extents->ul.x;
776 rect.y = extents->ul.y;
777 rect.width = extents->lr.x - rect.x + 1;
778 rect.height = extents->lr.y - rect.y + 1;
780 if( someWindow->mBounds.width == rect.width && someWindow->mBounds.height == rect.height )
781 return Pt_CONTINUE;
783 someWindow->mBounds.width = rect.width;
784 someWindow->mBounds.height = rect.height;
786 /* This enables the resize holdoff */
787 if( PtWidgetIsRealized( widget ) ) someWindow->OnResize( rect );
789 return Pt_CONTINUE;
793 /* catch an Ph_EV_INFO event when the graphics mode has changed */
794 int nsWindow::EvInfo( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo ) {
796 if( cbinfo->event && cbinfo->event->type == Ph_EV_INFO && cbinfo->event->subtype == Ph_OFFSCREEN_INVALID ) {
797 nsresult rv;
799 nsCOMPtr<nsIPrefBranch> pPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
800 if (NS_SUCCEEDED(rv)) {
801 PRBool displayInternalChange = PR_FALSE;
802 pPrefs->GetBoolPref("browser.display.internaluse.graphics_changed", &displayInternalChange);
803 pPrefs->SetBoolPref("browser.display.internaluse.graphics_changed", !displayInternalChange);
805 nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
806 NS_ENSURE_TRUE(windowMediator, NS_ERROR_FAILURE);
808 nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
809 NS_ENSURE_SUCCESS(windowMediator->GetXULWindowEnumerator(nsnull, getter_AddRefs(windowEnumerator)), NS_ERROR_FAILURE);
811 PRBool more;
812 windowEnumerator->HasMoreElements(&more);
813 while(more) {
814 nsCOMPtr<nsISupports> nextWindow = nsnull;
815 windowEnumerator->GetNext(getter_AddRefs(nextWindow));
816 nsCOMPtr<nsIXULWindow> xulWindow(do_QueryInterface(nextWindow));
817 NS_ENSURE_TRUE(xulWindow, NS_ERROR_FAILURE);
819 nsCOMPtr<nsIDocShell> docShell;
820 xulWindow->GetDocShell(getter_AddRefs(docShell));
822 nsCOMPtr<nsIPresShell> presShell;
823 docShell->GetPresShell( getter_AddRefs(presShell) );
825 nsIViewManager* viewManager = presShell->GetViewManager();
826 NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
828 windowEnumerator->HasMoreElements(&more);
831 PtDamageWidget( widget );
833 return Pt_CONTINUE;
836 //-------------------------------------------------------------------------
838 // Move this component
840 //-------------------------------------------------------------------------
841 NS_METHOD nsWindow::Move( PRInt32 aX, PRInt32 aY ) {
843 if( mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY) )
844 return NS_OK;
846 mBounds.x = aX;
847 mBounds.y = aY;
849 switch( mWindowType ) {
850 case eWindowType_popup:
852 PhPoint_t offset, total_offset = { 0, 0 };
854 PtWidget_t *parent, *disjoint = PtFindDisjoint( mWidget->parent );
856 while( disjoint ) {
857 PtGetAbsPosition( disjoint, &offset.x, &offset.y );
858 total_offset.x += offset.x;
859 total_offset.y += offset.y;
860 if( PtWidgetIsClass( disjoint, PtWindow ) || PtWidgetIsClass( disjoint, PtServer ) ) break; /* Stop at the first PtWindow */
861 parent = PtWidgetParent(disjoint);
862 if( parent ) disjoint = PtFindDisjoint( parent );
863 else {
864 disjoint = parent;
865 break;
869 aX += total_offset.x;
870 aY += total_offset.y;
872 /* Add the Offset if the widget is offset from its parent.. */
873 PtWidgetOffset( mWidget->parent, &offset );
874 aX += offset.x;
875 aY += offset.y;
877 break;
879 case eWindowType_dialog:
880 case eWindowType_toplevel:
881 /* Offset to the current virtual console */
882 QueryVisible( );
883 aX += gConsoleRect.ul.x;
884 aY += gConsoleRect.ul.y;
885 break;
888 if( mWidget ) {
889 if(( mWidget->area.pos.x != aX ) || ( mWidget->area.pos.y != aY )) {
890 PhPoint_t pos = { aX, aY };
891 PtSetResource( mWidget, Pt_ARG_POS, &pos, 0 );
893 /* ATENTIE Remove when wojtek fixes PR:22930 in the photon library */
894 if( PtWidgetClass( mWidget ) == PtRegion ) PtSetResource( mWidget, Pt_ARG_REGION_OPAQUE, 0, Ph_EV_KEY );
898 return NS_OK;
901 int nsWindow::MenuRegionCallback( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo ) {
902 if( gRollupWidget && gRollupListener ) {
903 /* rollup the menu */
904 gRollupListener->Rollup(nsnull);
906 return Pt_CONTINUE;
909 NS_IMETHODIMP nsWindow::SetModal( PRBool aModal ) {
910 nsresult res = NS_ERROR_FAILURE;
912 if (!mWidget)
913 return NS_ERROR_FAILURE;
915 PtWidget_t *toplevel = PtFindDisjoint(mWidget);
916 if( !toplevel ) return NS_ERROR_FAILURE;
918 if( aModal ) {
919 PtModalStart();
920 res = NS_OK;
922 else {
923 PtModalEnd();
924 res = NS_OK;
927 return res;
931 inline nsIRegion *nsWindow::GetRegion()
933 nsIRegion *region = NULL;
934 nsresult res;
936 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
938 res = CallCreateInstance( kRegionCID, &region );
939 if (NS_SUCCEEDED(res)) region->Init();
941 NS_ASSERTION(NULL != region, "Null region context");
943 return region;
947 widget is a PtRegion representing the native widget for a menu - reset the mParent->mLastMenu
948 since it points to an widget being destroyed
950 int nsWindow::MenuRegionDestroyed( PtWidget_t *widget, void *data, PtCallbackInfo_t *cbinfo )
952 nsWindow *pWin = (nsWindow *) GetInstance( widget );
953 if( pWin ) {
954 nsWindow *parent = ( nsWindow * ) pWin->mParent;
955 if( parent && parent->mLastMenu == widget )
956 parent->mLastMenu = nsnull;
958 return Pt_CONTINUE;
961 NS_IMETHODIMP nsWindow::SetFocus(PRBool aRaise)
963 sFocusWidget = this;
965 if( PtIsFocused( mWidget ) == 2 ) return NS_OK;
967 if( mWidget ) {
968 PtWidget_t *disjoint;
969 disjoint = PtFindDisjoint( mWidget );
970 if( PtWidgetIsClass( disjoint, PtWindow ) ) {
971 if( !( PtWindowGetState( disjoint ) & Ph_WM_STATE_ISFOCUS ) ) {
972 nsWindow *pWin = (nsWindow *) GetInstance( disjoint );
973 pWin->GetAttention( -1 );
976 PtContainerGiveFocus( mWidget, NULL );
978 return NS_OK;
981 NS_IMETHODIMP nsWindow::MakeFullScreen(PRBool aFullScreen)
983 /* we can use static data here because there can be only one full-screen window at a time */
984 static unsigned short old_render_flags;
985 static PhPoint_t old_pos;
987 PtArg_t args[3];
989 if( aFullScreen ) {
990 unsigned short p, *pflags;
991 PhArea_t area;
993 PtSetArg( &args[0], Pt_ARG_WINDOW_RENDER_FLAGS, &pflags, 0 );
994 PtGetResources( mWidget, 1, args );
995 p = old_render_flags = *pflags; // save the render flags
996 p &= ~(Ph_WM_RENDER_TITLE|Ph_WM_RENDER_BORDER);
998 PtWidgetArea( mWidget, &area );
999 old_pos = area.pos;
1001 QueryVisible( );
1002 PtSetArg( &args[0], Pt_ARG_POS, &gConsoleRect.ul, 0 );
1003 PtSetArg( &args[1], Pt_ARG_WINDOW_RENDER_FLAGS, p, -1 );
1004 PtSetArg( &args[2], Pt_ARG_WINDOW_STATE, Ph_WM_STATE_ISFRONT, Ph_WM_STATE_ISFRONT );
1005 PtSetResources( mWidget, 3, args );
1007 else {
1008 PtSetArg( &args[0], Pt_ARG_POS, &old_pos, 0 );
1009 PtSetArg( &args[1], Pt_ARG_WINDOW_RENDER_FLAGS, old_render_flags, -1 ); /* restore the render flags to the previous value */
1010 PtSetArg( &args[2], Pt_ARG_WINDOW_STATE, Ph_WM_STATE_ISNORMAL, Ph_WM_STATE_ISFRONT|Ph_WM_STATE_ISNORMAL );
1011 PtSetResources( mWidget, 3, args );
1014 return nsBaseWidget::MakeFullScreen( aFullScreen );