 |
1 /* -*- Mode: C++; tab-width: 2; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
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/
9 *
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.
14 *
15 * The Original Code is mozilla.org code.
16 *
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.
21 *
22 * Contributor(s):
23 * Paul Ashford <arougthopher@lizardland.net>
24 * Sergei Dolgov <sergei_d@fi.tartu.ee>
25 * Fredrik Holmqvist <thesuckiestemail@yahoo.se>
26 *
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
38 *
39 * ***** END LICENSE BLOCK ***** */
40
41 #include "nsDebug.h"
42 #include "nsWindow.h"
43 #include "nsIAppShell.h"
44 #include "nsIFontMetrics.h"
45 #include "nsFont.h"
46 #include "nsGUIEvent.h"
47 #include "nsWidgetsCID.h"
48 #include "nsIDragService.h"
49 #include "nsIDragSessionBeOS.h"
50 #include "nsIDeviceContext.h"
51 #include "nsRect.h"
52 #include "nsIRegion.h"
53 #include "nsTransform2D.h"
54 #include "nsGfxCIID.h"
55 #include "resource.h"
56 #include "prtime.h"
57 #include "nsReadableUtils.h"
58 #include "nsVoidArray.h"
59
60 #include <Application.h>
61 #include <InterfaceDefs.h>
62 #include <Region.h>
63 #include <ScrollBar.h>
64 #include <app/Message.h>
65 #include <support/String.h>
66 #include <Screen.h>
67
68 #include <nsBeOSCursors.h>
69 #if defined(BeIME)
70 #include <Input.h>
71 #include <InputServerMethod.h>
72 #include <String.h>
73 #endif
74
75 #include "nsIRollupListener.h"
76 #include "nsIMenuRollup.h"
77
78 // See comments in nsWindow.h as to why we override these calls from nsBaseWidget
79 NS_IMPL_THREADSAFE_ADDREF(nsWindow)
80 NS_IMPL_THREADSAFE_RELEASE(nsWindow)
81
82 static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID);
83 static NS_DEFINE_IID(kRegionCID, NS_REGION_CID);
84 static NS_DEFINE_IID(kCDragServiceCID, NS_DRAGSERVICE_CID);
85 //-------------------------------------------------------------------------
86 // Global Definitions
87 //-------------------------------------------------------------------------
88
89 // Rollup Listener - static variable defintions
90 static nsIRollupListener * gRollupListener = nsnull;
91 static nsIWidget * gRollupWidget = nsnull;
92 static PRBool gRollupConsumeRollupEvent = PR_FALSE;
93 // Tracking last activated BWindow
94 static BWindow * gLastActiveWindow = NULL;
95
96 // BCursor objects can't be created until they are used. Some mozilla utilities,
97 // such as regxpcom, do not create a BApplication object, and therefor fail to run.,
98 // since a BCursor requires a vaild BApplication (see Bug#129964). But, we still want
99 // to cache them for performance. Currently, there are 17 cursors available;
100 static nsVoidArray gCursorArray(21);
101 // Used in contrain position. Specifies how much of a window must remain on screen
102 #define kWindowPositionSlop 20
103 // BeOS does not provide this information, so we must hard-code it
104 #define kWindowBorderWidth 5
105 #define kWindowTitleBarHeight 24
106
107
108 #if defined(BeIME)
109 #include "nsUTF8Utils.h"
110 static inline uint32 utf8_str_len(const char* ustring, int32 length)
111 {
112 CalculateUTF8Length cutf8;
113 cutf8.write(ustring, length);
114 return cutf8.Length();
115 }
116
117 nsIMEBeOS::nsIMEBeOS()
118 : imeTarget(NULL)
119 , imeState(NS_COMPOSITION_END), imeWidth(14)
120 {
121 }
122 /* placeholder for possible cleanup
123 nsIMEBeOS::~nsIMEBeOS()
124 {
125 }
126 */
127 void nsIMEBeOS::RunIME(uint32 *args, nsWindow *target, BView *fView)
128 {
129 BMessage msg;
130 msg.Unflatten((const char*)args);
131
132 switch (msg.FindInt32("be:opcode"))
133 {
134 case B_INPUT_METHOD_CHANGED:
135 if (msg.HasString("be:string"))
136 {
137 const char* src = msg.FindString("be:string");
138 CopyUTF8toUTF16(src, imeText);
139
140 if (msg.FindBool("be:confirmed"))
141 {
142 if (imeState != NS_COMPOSITION_END)
143 DispatchText(imeText, 0, NULL);
144 }
145 else
146 {
147 nsTextRange txtRuns[2];
148 PRUint32 txtCount = 2;
149
150 int32 select[2];
151 select[0] = msg.FindInt32("be:selection", int32(0));
152 select[1] = msg.FindInt32("be:selection", 1);
153
154 txtRuns[0].mStartOffset = (select[0] == select[1]) ? 0 : utf8_str_len(src, select[1]);
155 txtRuns[0].mEndOffset = imeText.Length();
156 txtRuns[0].mRangeType = NS_TEXTRANGE_CONVERTEDTEXT;
157 if (select[0] == select[1])
158 txtCount = 1;
159 else
160 {
161 txtRuns[1].mStartOffset = utf8_str_len(src, select[0]);
162 txtRuns[1].mEndOffset = utf8_str_len(src, select[1]);
163 txtRuns[1].mRangeType = NS_TEXTRANGE_SELECTEDCONVERTEDTEXT;
164 }
165 imeTarget = target;
166 DispatchText(imeText, txtCount, txtRuns);
167 }
168 }
169 break;
170
171 case B_INPUT_METHOD_LOCATION_REQUEST:
172 if (fView && fView->LockLooper())
173 {
174 BPoint caret(imeCaret);
175 DispatchIME(NS_COMPOSITION_QUERY);
176 if (caret.x > imeCaret.x)
177 caret.x = imeCaret.x - imeWidth * imeText.Length(); /* back */
178
179 BMessage reply(B_INPUT_METHOD_EVENT);
180 reply.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
181 for (int32 s= 0; imeText[s]; s++)
182 {
183 reply.AddPoint("be:location_reply", fView->ConvertToScreen(caret));
184 reply.AddFloat("be:height_reply", imeHeight);
185 caret.x += imeWidth;
186 }
187 imeMessenger.SendMessage(&reply);
188 fView->UnlockLooper();
189 }
190 break;
191
192 case B_INPUT_METHOD_STARTED:
193 imeTarget = target;
194 DispatchIME(NS_COMPOSITION_START);
195 DispatchIME(NS_COMPOSITION_QUERY);
196
197 msg.FindMessenger("be:reply_to", &imeMessenger);
198 break;
199
200 case B_INPUT_METHOD_STOPPED:
201 if (imeState != NS_COMPOSITION_END)
202 DispatchIME(NS_COMPOSITION_END);
203 imeText.Truncate();
204 break;
205 };
206 }
207
208 void nsIMEBeOS::DispatchText(nsString &text, PRUint32 txtCount, nsTextRange* txtRuns)
209 {
210 nsTextEvent textEvent(PR_TRUE,NS_TEXT_TEXT, imeTarget);
211
212 textEvent.time = 0;
213 textEvent.isShift =
214 textEvent.isControl =
215 textEvent.isAlt =
216 textEvent.isMeta = PR_FALSE;
217
218 textEvent.refPoint.x =
219 textEvent.refPoint.y = 0;
220
221 textEvent.theText = text.get();
222 textEvent.isChar = PR_TRUE;
223 textEvent.rangeCount= txtCount;
224 textEvent.rangeArray= txtRuns;
225
226 DispatchWindowEvent(&textEvent);
227 }
228
229 void nsIMEBeOS::DispatchCancelIME()
230 {
231 if (imeText.Length() && imeState != NS_COMPOSITION_END)
232 {
233 BMessage reply(B_INPUT_METHOD_EVENT);
234 reply.AddInt32("be:opcode", B_INPUT_METHOD_STOPPED);
235 imeMessenger.SendMessage(&reply);
236
237 DispatchText(imeText, 0, NULL);
238 DispatchIME(NS_COMPOSITION_END);
239
240 imeText.Truncate();
241 }
242 }
243
244 void nsIMEBeOS::DispatchIME(PRUint32 what)
245 {
246 nsCompositionEvent compEvent(PR_TRUE, what, imeTarget);
247
248 compEvent.refPoint.x =
249 compEvent.refPoint.y = 0;
250 compEvent.time = 0;
251
252 DispatchWindowEvent(&compEvent);
253 imeState = what;
254
255 if (what == NS_COMPOSITION_QUERY)
256 {
257 imeCaret.Set(compEvent.theReply.mCursorPosition.x,
258 compEvent.theReply.mCursorPosition.y);
259 imeHeight = compEvent.theReply.mCursorPosition.height+4;
260 }
261 }
262
263 PRBool nsIMEBeOS::DispatchWindowEvent(nsGUIEvent* event)
264 {
265 nsEventStatus status;
266 imeTarget->DispatchEvent(event, status);
267 return PR_FALSE;
268 }
269 // There is only one IME instance per app, actually it may be set as global
270 nsIMEBeOS *nsIMEBeOS::GetIME()
271 {
272 if(beosIME == 0)
273 beosIME = new nsIMEBeOS();
274 return beosIME;
275 }
276 nsIMEBeOS *nsIMEBeOS::beosIME = 0;
277 #endif
278
279 //-------------------------------------------------------------------------
280 //
281 // nsWindow constructor
282 //
283 //-------------------------------------------------------------------------
284 nsWindow::nsWindow() : nsBaseWidget()
285 {
286 rgb_color back = ui_color(B_PANEL_BACKGROUND_COLOR);
287
288 mView = 0;
289 mPreferredWidth = 0;
290 mPreferredHeight = 0;
291 mFontMetrics = nsnull;
292 mIsVisible = PR_FALSE;
293 mEnabled = PR_TRUE;
294 mIsScrolling = PR_FALSE;
295 mParent = nsnull;
296 mWindowParent = nsnull;
297 mUpdateArea = do_CreateInstance(kRegionCID);
298 mForeground = NS_RGBA(0xFF,0xFF,0xFF,0xFF);
299 mBackground = mForeground;
300 mBWindowFeel = B_NORMAL_WINDOW_FEEL;
301 if (mUpdateArea)
302 {
303 mUpdateArea->Init();
304 mUpdateArea->SetTo(0, 0, 0, 0);
305 }
306 }
307
308
309 //-------------------------------------------------------------------------
310 //
311 // nsWindow destructor
312 //
313 //-------------------------------------------------------------------------
314 nsWindow::~nsWindow()
315 {
316 mIsDestroying = PR_TRUE;
317
318 // If the widget was released without calling Destroy() then the native
319 // window still exists, and we need to destroy it
320 if (NULL != mView)
321 {
322 Destroy();
323 }
324 NS_IF_RELEASE(mFontMetrics);
325 }
326
327 NS_METHOD nsWindow::BeginResizingChildren(void)
328 {
329 // HideKids(PR_TRUE) may be used here
330 NS_NOTYETIMPLEMENTED("BeginResizingChildren not yet implemented"); // to be implemented
331 return NS_OK;
332 }
333
334 NS_METHOD nsWindow::EndResizingChildren(void)
335 {
336 // HideKids(PR_FALSE) may be used here
337 NS_NOTYETIMPLEMENTED("EndResizingChildren not yet implemented"); // to be implemented
338 return NS_OK;
339 }
340
341 NS_METHOD nsWindow::WidgetToScreen(const nsRect& aOldRect, nsRect& aNewRect)
342 {
343 BPoint point;
344 point.x = aOldRect.x;
345 point.y = aOldRect.y;
346 if (mView && mView->LockLooper())
347 {
348 mView->ConvertToScreen(&point);
349 mView->UnlockLooper();
350 }
351 aNewRect.x = nscoord(point.x);
352 aNewRect.y = nscoord(point.y);
353 aNewRect.width = aOldRect.width;
354 aNewRect.height = aOldRect.height;
355 return NS_OK;
356 }
357
358 NS_METHOD nsWindow::ScreenToWidget(const nsRect& aOldRect, nsRect& aNewRect)
359 {
360 BPoint point;
361 point.x = aOldRect.x;
362 point.y = aOldRect.y;
363 if (mView && mView->LockLooper())
364 {
365 mView->ConvertFromScreen(&point);
366 mView->UnlockLooper();
367 }
368 aNewRect.x = nscoord(point.x);
369 aNewRect.y = nscoord(point.y);
370 aNewRect.width = aOldRect.width;
371 aNewRect.height = aOldRect.height;
372 return NS_OK;
373 }
374
375
376 //-------------------------------------------------------------------------
377 //
378 // Convert nsEventStatus value to a windows boolean
379 //
380 //-------------------------------------------------------------------------
381
382 PRBool nsWindow::ConvertStatus(nsEventStatus aStatus)
383 {
384 switch(aStatus)
385 {
386 case nsEventStatus_eIgnore:
387 return PR_FALSE;
388 case nsEventStatus_eConsumeNoDefault:
389 return PR_TRUE;
390 case nsEventStatus_eConsumeDoDefault:
391 return PR_FALSE;
392 default:
393 NS_ASSERTION(0, "Illegal nsEventStatus enumeration value");
394 break;
395 }
396 return PR_FALSE;
397 }
398
399 //-------------------------------------------------------------------------
400 //
401 // Initialize an event to dispatch
402 //
403 //-------------------------------------------------------------------------
404 void nsWindow::InitEvent(nsGUIEvent& event, nsPoint* aPoint)
405 {
406 NS_ADDREF(event.widget);
407
408 if (nsnull == aPoint) // use the point from the event
409 {
410 // get the message position in client coordinates and in twips
411 event.point.x = 0;
412 event.point.y = 0;
413 }
414 else // use the point override if provided
415 {
416 event.point.x = aPoint->x;
417 event.point.y = aPoint->y;
418 }
419 event.time = PR_IntervalNow();
420 }
421
422 //-------------------------------------------------------------------------
423 //
424 // Invokes callback and ProcessEvent method on Event Listener object
425 //
426 //-------------------------------------------------------------------------
427 NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus & aStatus)
428 {
429 aStatus = nsEventStatus_eIgnore;
430
431 nsCOMPtr <nsIWidget> mWidget = event->widget;
432
433 if (mEventCallback)
434 aStatus = (*mEventCallback)(event);
435
436 if ((aStatus != nsEventStatus_eIgnore) && (mEventListener))
437 aStatus = mEventListener->ProcessEvent(*event);
438
439 return NS_OK;
440 }
441
442 //-------------------------------------------------------------------------
443 //
444 // Dispatch Window Event
445 //
446 //-------------------------------------------------------------------------
447 PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
448 {
449 nsEventStatus status;
450 DispatchEvent(event, status);
451 return ConvertStatus(status);
452 }
453
454 //-------------------------------------------------------------------------
455 //
456 // Dispatch standard event
457 //
458 //-------------------------------------------------------------------------
459
460 PRBool nsWindow::DispatchStandardEvent(PRUint32 aMsg)
461 {
462 nsGUIEvent event(PR_TRUE, aMsg, this);
463 InitEvent(event);
464
465 PRBool result = DispatchWindowEvent(&event);
466 NS_RELEASE(event.widget);
467 return result;
468 }
469
470 NS_IMETHODIMP nsWindow::PreCreateWidget(nsWidgetInitData *aInitData)
471 {
472 if ( nsnull == aInitData)
473 return NS_ERROR_FAILURE;
474
475 SetWindowType(aInitData->mWindowType);
476 SetBorderStyle(aInitData->mBorderStyle);
477 return NS_OK;
478 }
479
480 //-------------------------------------------------------------------------
481 //
482 // Utility method for implementing both Create(nsIWidget ...) and
483 // Create(nsNativeWidget...)
484 //-------------------------------------------------------------------------
485 nsresult nsWindow::StandardWindowCreate(nsIWidget *aParent,
486 const nsRect &aRect,
487 EVENT_CALLBACK aHandleEventFunction,
488 nsIDeviceContext *aContext,
489 nsIAppShell *aAppShell,
490 nsIToolkit *aToolkit,
491 nsWidgetInitData *aInitData,
492 nsNativeWidget aNativeParent)
493 {
494
495 //Do as little as possible for invisible windows, why are these needed?
496 if (mWindowType == eWindowType_invisible)
497 return NS_ERROR_FAILURE;
498
499 nsIWidget *baseParent =
500 (aInitData->mWindowType == eWindowType_dialog ||
501 aInitData->mWindowType == eWindowType_toplevel ||
502 aInitData->mWindowType == eWindowType_invisible) ?
503 nsnull : aParent;
504
505 NS_ASSERTION(aInitData->mWindowType != eWindowType_popup ||
506 !aParent, "Popups should not be hooked into nsIWidget hierarchy");
507
508 mIsTopWidgetWindow = (nsnull == baseParent);
509
510 BaseCreate(baseParent, aRect, aHandleEventFunction, aContext,
511 aAppShell, aToolkit, aInitData);
512
513 mListenForResizes = aNativeParent ? PR_TRUE : aInitData->mListenForResizes;
514
515 // Switch to the "main gui thread" if necessary... This method must
516 // be executed on the "gui thread"...
517 //
518 nsToolkit* toolkit = (nsToolkit *)mToolkit;
519 if (toolkit && !toolkit->IsGuiThread())
520 {
521 uint32 args[7];
522 args[0] = (uint32)aParent;
523 args[1] = (uint32)&aRect;
524 args[2] = (uint32)aHandleEventFunction;
525 args[3] = (uint32)aContext;
526 args[4] = (uint32)aAppShell;
527 args[5] = (uint32)aToolkit;
528 args[6] = (uint32)aInitData;
529
530 if (nsnull != aParent)
531 {
532 // nsIWidget parent dispatch
533 MethodInfo info(this, this, nsSwitchToUIThread::CREATE, 7, args);
534 toolkit->CallMethod(&info);
535 }
536 else
537 {
538 // Native parent dispatch
539 MethodInfo info(this, this, nsSwitchToUIThread::CREATE_NATIVE, 5, args);
540 toolkit->CallMethod(&info);
541 }
542 return NS_OK;
543 }
544
545 mParent = aParent;
546 // Useful shortcut, wondering if we can use it also in GetParent() instead nsIWidget* type mParent.
547 mWindowParent = (nsWindow *)aParent;
548 SetBounds(aRect);
549
550 BRect winrect = BRect(aRect.x, aRect.y, aRect.x + aRect.width - 1, aRect.y + aRect.height - 1);
551
552 // Default mode for window, everything switched off.
553 uint32 flags = B_NOT_RESIZABLE | B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE | B_NOT_CLOSABLE | B_ASYNCHRONOUS_CONTROLS;
554 window_look look = B_NO_BORDER_WINDOW_LOOK;
555 switch (mWindowType)
556 {
557 //handle them as childviews until I know better. Shame on me.
558 case eWindowType_java:
559 case eWindowType_plugin:
560 NS_NOTYETIMPLEMENTED("Java and plugin windows not yet implemented properly trying childview"); // to be implemented
561 //These fall thru and behave just like child for the time being. They may require special implementation.
562 case eWindowType_child:
563 {
564 //NS_NATIVE_GRAPHIC maybe?
565 //Parent may be a BView if we embed.
566 BView *parent= (BView *) (aParent ? aParent->GetNativeData(NS_NATIVE_WIDGET) : aNativeParent);
567 //There seems to be three of these on startup,
568 //but I believe that these are because of bugs in
569 //other code as they existed before rewriting this
570 //function.
571 NS_PRECONDITION(parent, "Childviews without parents don't get added to anything.");
572 // A childview that is never added to a parent is very strange.
573 if (!parent)
574 return NS_ERROR_FAILURE;
575
576 mView = new nsViewBeOS(this, winrect, "Child view", 0, B_WILL_DRAW);
577 #if defined(BeIME)
578 mView->SetFlags(mView->Flags() | B_INPUT_METHOD_AWARE);
579 #endif
580 bool mustUnlock = parent->Parent() && parent->LockLooper();
581 parent->AddChild(mView);
582 if (mustUnlock) parent->UnlockLooper();
583 DispatchStandardEvent(NS_CREATE);
584 return NS_OK;
585 }
586
587 case eWindowType_popup:
588 case eWindowType_dialog:
589 case eWindowType_toplevel:
590 {
591 //eBorderStyle_default is to ask the OS to handle it as it sees best.
592 //eBorderStyle_all is same as top_level window default.
593 if (eBorderStyle_default == mBorderStyle || eBorderStyle_all & mBorderStyle)
594 {
595 //(Firefox prefs doesn't go this way, so apparently it wants titlebar, zoom, resize and close.)
596
597 //Look and feel for others are set ok at init.
598 if (eWindowType_toplevel==mWindowType)
599 {
600 look = B_TITLED_WINDOW_LOOK;
601 flags = B_ASYNCHRONOUS_CONTROLS;
602 }
603 }
604 else
605 {
606 if (eBorderStyle_border & mBorderStyle)
607 look = B_MODAL_WINDOW_LOOK;
608
609 if (eBorderStyle_resizeh & mBorderStyle)
610 {
611 //Resize demands at least border
612 look = B_MODAL_WINDOW_LOOK;
613 flags &= !B_NOT_RESIZABLE;
614 }
615
616 //We don't have titlebar menus, so treat like title as it demands titlebar.
617 if (eBorderStyle_title & mBorderStyle || eBorderStyle_menu & mBorderStyle)
618 look = B_TITLED_WINDOW_LOOK;
619
620 if (eBorderStyle_minimize & mBorderStyle)
621 flags &= !B_NOT_MINIMIZABLE;
622
623 if (eBorderStyle_maximize & mBorderStyle)
624 flags &= !B_NOT_ZOOMABLE;
625
626 if (eBorderStyle_close & mBorderStyle)
627 flags &= !B_NOT_CLOSABLE;
628 }
629
630 //popups always avoid focus and don't force the user to another workspace.
631 if (eWindowType_popup==mWindowType)
632 flags |= B_AVOID_FOCUS | B_NO_WORKSPACE_ACTIVATION;
633
634 nsWindowBeOS * w = new nsWindowBeOS(this, winrect, "", look, mBWindowFeel, flags);
635 if (!w)
636 return NS_ERROR_OUT_OF_MEMORY;
637
638 mView = new nsViewBeOS(this, w->Bounds(), "Toplevel view", B_FOLLOW_ALL, (mWindowType == eWindowType_popup ? B_WILL_DRAW: 0));
639
640 if (!mView)
641 return NS_ERROR_OUT_OF_MEMORY;
642
643 w->AddChild(mView);
644 // I'm wondering if we can move part of that code to above
645 if (eWindowType_dialog == mWindowType && mWindowParent)
646 {
647 nsWindow *topparent = mWindowParent;
648 while(topparent->mWindowParent)
649 topparent = topparent->mWindowParent;
650 // may be got via mView and mView->Window() of topparent explicitly
651 BWindow* subsetparent = (BWindow *)topparent->GetNativeData(NS_NATIVE_WINDOW);
652 if (subsetparent)
653 {
654 mBWindowFeel = B_FLOATING_SUBSET_WINDOW_FEEL;
655 w->SetFeel(mBWindowFeel);
656 w->AddToSubset(subsetparent);
657 }
658 }
659 else if (eWindowType_popup == mWindowType && aNativeParent)
660 {
661 // Due poor BeOS capability to control windows hierarchy/z-order we use this workaround
662 // to show eWindowType_popup (e.g. drop-downs) over floating (subset) parent window.
663 if (((BView *)aNativeParent)->Window() && ((BView *)aNativeParent)->Window()->IsFloating())
664 {
665 mBWindowFeel = B_FLOATING_ALL_WINDOW_FEEL;
666 w->SetFeel(mBWindowFeel);
667 }
668 }
669
670 DispatchStandardEvent(NS_CREATE);
671 return NS_OK;
672 }
673 case eWindowType_invisible:
674 case eWindowType_sheet:
675 break;
676 default:
677 {
678 printf("UNKNOWN or not handled windowtype!!!\n");
679 }
680 }
681
682 return NS_ERROR_FAILURE;
683 }
684
685 //-------------------------------------------------------------------------
686 //
687 // Create the proper widget
688 //
689 //-------------------------------------------------------------------------
690 NS_METHOD nsWindow::Create(nsIWidget *aParent,
691 const nsRect &aRect,
692 EVENT_CALLBACK aHandleEventFunction,
693 nsIDeviceContext *aContext,
694 nsIAppShell *aAppShell,
695 nsIToolkit *aToolkit,
696 nsWidgetInitData *aInitData)
697 {
698 return(StandardWindowCreate(aParent, aRect, aHandleEventFunction,
699 aContext, aAppShell, aToolkit, aInitData,
700 nsnull));
701 }
702
703
704 //-------------------------------------------------------------------------
705 //
706 // create with a native parent
707 //
708 //-------------------------------------------------------------------------
709
710 NS_METHOD nsWindow::Create(nsNativeWidget aParent,
711 const nsRect &aRect,
712 EVENT_CALLBACK aHandleEventFunction,
713 nsIDeviceContext *aContext,
714 nsIAppShell *aAppShell,
715 nsIToolkit *aToolkit,
716 nsWidgetInitData *aInitData)
717 {
718 return(StandardWindowCreate(nsnull, aRect, aHandleEventFunction,
719 aContext, aAppShell, aToolkit, aInitData,
720 aParent));
721 }
722
723 //-------------------------------------------------------------------------
724 //
725 // Close this nsWindow
726 //
727 //-------------------------------------------------------------------------
728 NS_METHOD nsWindow::Destroy()
729 {
730 // Switch to the "main gui thread" if necessary... This method must
731 // be executed on the "gui thread"...
732 nsToolkit* toolkit = (nsToolkit *)mToolkit;
733 if (toolkit != nsnull && !toolkit->IsGuiThread())
734 {
735 MethodInfo info(this, this, nsSwitchToUIThread::DESTROY);
736 toolkit->CallMethod(&info);
737 return NS_ERROR_FAILURE;
738 }
739
740 // Ok, now tell the nsBaseWidget class to clean up what it needs to
741 if (!mIsDestroying)
742 {
743 nsBaseWidget::Destroy();
744 }
745 //our windows can be subclassed by
746 //others and these namless, faceless others
747 //may not let us know about WM_DESTROY. so,
748 //if OnDestroy() didn't get called, just call
749 //it now.
750 if (PR_FALSE == mOnDestroyCalled)
751 OnDestroy();
752
753 // Destroy the BView, if no mView, it is probably destroyed before
754 // automatically with BWindow::Quit()
755 if (mView)
756 {
757 // prevent the widget from causing additional events
758 mEventCallback = nsnull;
759
760 if (mView->LockLooper())
761 {
762 while(mView->ChildAt(0))
763 mView->RemoveChild(mView->ChildAt(0));
764 // destroy from inside
765 BWindow *w = mView->Window();
766 // if no window, it was destroyed as result of B_QUIT_REQUESTED and
767 // took also all its children away
768 if (w)
769 {
770 w->Sync();
771 if (mView->Parent())
772 {
773 mView->Parent()->RemoveChild(mView);
774 if (eWindowType_child != mWindowType)
775 w->Quit();
776 else
777 w->Unlock();
778 }
779 else
780 {
781 w->RemoveChild(mView);
782 w->Quit();
783 }
784 }
785 else
786 mView->RemoveSelf();
787
788 delete mView;
789 }
790
791 // window is already gone
792 mView = NULL;
793 }
794 mParent = nsnull;
795 mWindowParent = nsnull;
796 return NS_OK;}
797
798
799 //-------------------------------------------------------------------------
800 //
801 // Get this nsWindow parent
802 //
803 //-------------------------------------------------------------------------
804 nsIWidget* nsWindow::GetParent(void)
805 {
806 //We cannot addref mParent directly
807 nsIWidget *widget = 0;
808 if (mIsDestroying || mOnDestroyCalled)
809 return nsnull;
810 widget = (nsIWidget *)mParent;
811 NS_IF_ADDREF(widget);
812 return widget;
813 }
814
815
816 //-------------------------------------------------------------------------
817 //
818 // Hide or show this component
819 //
820 //-------------------------------------------------------------------------
821 NS_METHOD nsWindow::Show(PRBool bState)
822 {
823 if (!mEnabled)
824 return NS_OK;
825 if (mView && mView->LockLooper())
826 {
827 switch (mWindowType)
828 {
829 case eWindowType_popup:
830 {
831 if (PR_FALSE == bState)
832 {
833 // XXX BWindow::Hide() is needed ONLY for popups. No need to hide views for popups
834 if (mView->Window() && !mView->Window()->IsHidden())
835 mView->Window()->Hide();
836 }
837 else
838 {
839 if (mView->Window())
840 {
841 // bring menu to current workspace - Bug 310293
842 mView->Window()->SetWorkspaces(B_CURRENT_WORKSPACE);
843 if (mView->Window()->IsHidden())
844 mView->Window()->Show();
845 }
846 }
847 break;
848 }
849
850 case eWindowType_child:
851 {
852 // XXX No BWindow deals for children
853 if (PR_FALSE == bState)
854 {
855 if (!mView->IsHidden())
856 mView->Hide();
857 }
858 else
859 {
860 if (mView->IsHidden())
861 mView->Show();
862 }
863 break;
864 }
865
866 case eWindowType_dialog:
867 case eWindowType_toplevel:
868 {
869 if (bState == PR_FALSE)
870 {
871 if (mView->Window() && !mView->Window()->IsHidden())
872 mView->Window()->Hide();
873 }
874 else
875 {
876 if (mView->Window() && mView->Window()->IsHidden())
877 mView->Window()->Show();
878 }
879 break;
880 }
881
882 default: // toplevel and dialog
883 {
884 NS_ASSERTION(false, "Unhandled Window Type in nsWindow::Show()!");
885 break;
886 }
887 } //end switch
888
889 mView->UnlockLooper();
890 mIsVisible = bState;
891 }
892 return NS_OK;
893 }
894 //-------------------------------------------------------------------------
895 // Set/unset mouse capture
896 //-------------------------------------------------------------------------
897 NS_METHOD nsWindow::CaptureMouse(PRBool aCapture)
898 {
899 if (mView && mView->LockLooper())
900 {
901 if (PR_TRUE == aCapture)
902 mView->SetEventMask(B_POINTER_EVENTS);
903 else
904 mView->SetEventMask(0);
905 mView->UnlockLooper();
906 }
907 return NS_OK;
908 }
909 //-------------------------------------------------------------------------
910 // Capture Roolup Events
911 //-------------------------------------------------------------------------
912 NS_METHOD nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent)
913 {
914 if (!mEnabled)
915 return NS_OK;
916
917 if (aDoCapture)
918 {
919 // we haven't bothered carrying a weak reference to gRollupWidget because
920 // we believe lifespan is properly scoped. this next assertion helps
921 // assure that remains true.
922 NS_ASSERTION(!gRollupWidget, "rollup widget reassigned before release");
923 gRollupConsumeRollupEvent = aConsumeRollupEvent;
924 NS_IF_RELEASE(gRollupListener);
925 NS_IF_RELEASE(gRollupWidget);
926 gRollupListener = aListener;
927 NS_ADDREF(aListener);
928 gRollupWidget = this;
929 NS_ADDREF(this);
930 }
931 else
932 {
933 NS_IF_RELEASE(gRollupListener);
934 NS_IF_RELEASE(gRollupWidget);
935 }
936
937 return NS_OK;
938 }
939
940 //-------------------------------------------------------------------------
941 // Check if event happened inside the given nsWindow
942 //-------------------------------------------------------------------------
943 PRBool nsWindow::EventIsInsideWindow(nsWindow* aWindow, nsPoint pos)
944 {
945 BRect r;
946 BWindow *window = (BWindow *)aWindow->GetNativeData(NS_NATIVE_WINDOW);
947 if (window)
948 {
949 r = window->Frame();
950 }
951 else
952 {
953 // Bummer!
954 return PR_FALSE;
955 }
956
957 if (pos.x < r.left || pos.x > r.right ||
958 pos.y < r.top || pos.y > r.bottom) {
959 return PR_FALSE;
960 }
961
962 return PR_TRUE;
963 }
964
965 //-------------------------------------------------------------------------
966 // DealWithPopups
967 //
968 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
969 //-------------------------------------------------------------------------
970 PRBool
971 nsWindow::DealWithPopups(uint32 methodID, nsPoint pos)
972 {
973 if (gRollupListener && gRollupWidget)
974 {
975 // Rollup if the event is outside the popup.
976 PRBool rollup = !nsWindow::EventIsInsideWindow((nsWindow*)gRollupWidget, pos);
977
978 // If we're dealing with menus, we probably have submenus and we don't
979 // want to rollup if the click is in a parent menu of the current submenu.
980 if (rollup)
981 {
982 nsCOMPtr<nsIMenuRollup> menuRollup ( do_QueryInterface(gRollupListener) );
983 if ( menuRollup )
984 {
985 nsCOMPtr<nsISupportsArray> widgetChain;
986 menuRollup->GetSubmenuWidgetChain ( getter_AddRefs(widgetChain) );
987 if ( widgetChain )
988 {
989 PRUint32 count = 0;
990 widgetChain->Count(&count);
991 for ( PRUint32 i = 0; i < count; ++i )
992 {
993 nsCOMPtr<nsISupports> genericWidget;
994 widgetChain->GetElementAt ( i, getter_AddRefs(genericWidget) );
995 nsCOMPtr<nsIWidget> widget ( do_QueryInterface(genericWidget) );
996 if ( widget )
997 {
998 nsIWidget* temp = widget.get();
999 if ( nsWindow::EventIsInsideWindow((nsWindow*)temp, pos) )
1000 {
1001 rollup = PR_FALSE;
1002 break;
1003 }
1004 }
1005 } // foreach parent menu widget
1006 } // if widgetChain
1007 } // if rollup listener knows about menus
1008 } // if rollup
1009
1010 if (rollup)
1011 {
1012 gRollupListener->Rollup();
1013
1014 if (gRollupConsumeRollupEvent)
1015 {
1016 return PR_TRUE;
1017 }
1018 }
1019 } // if rollup listeners registered
1020
1021 return PR_FALSE;
1022 }
1023
1024
1025 //-------------------------------------------------------------------------
1026 //
1027 // IsVisible
1028 //
1029 // Return PR_TRUE if the whether the component is visible, PR_FALSE otherwise
1030 //-------------------------------------------------------------------------
1031 NS_METHOD nsWindow::IsVisible(PRBool & bState)
1032 {
1033 bState = mIsVisible;
1034 return NS_OK;
1035 }
1036
1037 //-------------------------------------------------------------------------
1038 //
1039 // Sanity check potential move coordinates
1040 //
1041 //-------------------------------------------------------------------------
1042 NS_METHOD nsWindow::ConstrainPosition(PRBool aAllowSlop, PRInt32 *aX, PRInt32 *aY)
1043 {
1044 if (mIsTopWidgetWindow && mView->Window())
1045 {
1046 BScreen screen;
1047 // If no valid screen, just return
1048 if (! screen.IsValid()) return NS_OK;
1049
1050 BRect screen_rect = screen.Frame();
1051 BRect win_bounds = mView->Window()->Frame();
1052
1053 #ifdef DEBUG_CONSTRAIN_POSITION
1054 printf("ConstrainPosition: allowSlop=%s, x=%d, y=%d\n\tScreen :", (aAllowSlop?"T":"F"),*aX,*aY);
1055 screen_rect.PrintToStream();
1056 printf("\tWindow: ");
1057 win_bounds.PrintToStream();
1058 #endif
1059
1060 if (aAllowSlop)
1061 {
1062 if (*aX < kWindowPositionSlop - win_bounds.IntegerWidth() + kWindowBorderWidth)
1063 *aX = kWindowPositionSlop - win_bounds.IntegerWidth() + kWindowBorderWidth;
1064 else if (*aX > screen_rect.IntegerWidth() - kWindowPositionSlop - kWindowBorderWidth)
1065 *aX = screen_rect.IntegerWidth() - kWindowPositionSlop - kWindowBorderWidth;
1066
1067 if (*aY < kWindowPositionSlop - win_bounds.IntegerHeight() + kWindowTitleBarHeight)
1068 *aY = kWindowPositionSlop - win_bounds.IntegerHeight() + kWindowTitleBarHeight;
1069 else if (*aY > screen_rect.IntegerHeight() - kWindowPositionSlop - kWindowBorderWidth)
1070 *aY = screen_rect.IntegerHeight() - kWindowPositionSlop - kWindowBorderWidth;
1071
1072 }
1073 else
1074 {
1075
1076 if (*aX < kWindowBorderWidth)
1077 *aX = kWindowBorderWidth;
1078 else if (*aX > screen_rect.IntegerWidth() - win_bounds.IntegerWidth() - kWindowBorderWidth)
1079 *aX = screen_rect.IntegerWidth() - win_bounds.IntegerWidth() - kWindowBorderWidth;
1080
1081 if (*aY < kWindowTitleBarHeight)
1082 *aY = kWindowTitleBarHeight;
1083 else if (*aY > screen_rect.IntegerHeight() - win_bounds.IntegerHeight() - kWindowBorderWidth)
1084 *aY = screen_rect.IntegerHeight() - win_bounds.IntegerHeight() - kWindowBorderWidth;
1085 }
1086 }
1087 return NS_OK;
1088 }
1089
1090 void nsWindow::HideKids(PRBool state)
1091 {
1092 for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling())
1093 {
1094 nsWindow *childWidget = NS_STATIC_CAST(nsWindow*, kid);
1095 nsRect kidrect = ((nsWindow *)kid)->mBounds;
1096 //Don't bother about invisible
1097 if (mBounds.Intersects(kidrect))
1098 {
1099 childWidget->Show(!state);
1100 }
1101 }
1102 }
1103
1104 //-------------------------------------------------------------------------
1105 //
1106 // Move this component
1107 //
1108 //-------------------------------------------------------------------------
1109 nsresult nsWindow::Move(PRInt32 aX, PRInt32 aY)
1110 {
1111 // Only perform this check for non-popup windows, since the positioning can
1112 // in fact change even when the x/y do not. We always need to perform the
1113 // check. See bug #97805 for details.
1114 if (mWindowType != eWindowType_popup && (mBounds.x == aX) && (mBounds.y == aY))
1115 {
1116 // Nothing to do, since it is already positioned correctly.
1117 return NS_OK;
1118 }
1119
1120
1121 // Set cached value for lightweight and printing
1122 mBounds.x = aX;
1123 mBounds.y = aY;
1124
1125 // We may reset children visibility here, but it needs special care
1126 // - see comment 18 in Bug 311651. More sofisticated code needed.
1127
1128 // until we lack separate window and widget, we "cannot" move BWindow without BView
1129 if(mView && mView->LockLooper())
1130 {
1131 if(mView->Parent() || !mView->Window())
1132 mView->MoveTo(aX, aY);
1133 else
1134 ((nsWindowBeOS *)mView->Window())->MoveTo(aX, aY);
1135
1136 mView->UnlockLooper();
1137 }
1138
1139 OnMove(aX,aY);
1140
1141 return NS_OK;
1142 }
1143
1144
1145
1146 //-------------------------------------------------------------------------
1147 //
1148 // Resize this component
1149 //
1150 //-------------------------------------------------------------------------
1151 NS_METHOD nsWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
1152 {
1153
1154 if (aWidth < 0 || aHeight < 0)
1155 return NS_OK;
1156
1157 mBounds.width = aWidth;
1158 mBounds.height = aHeight;
1159
1160 // until we lack separate window and widget, we "cannot" resize BWindow without BView
1161 if (mView && mView->LockLooper())
1162 {
1163 if (mView->Parent() || !mView->Window())
1164 mView->ResizeTo(aWidth - 1, aHeight - 1);
1165 else
1166 ((nsWindowBeOS *)mView->Window())->ResizeTo(aWidth - 1, aHeight - 1);
1167
1168 mView->UnlockLooper();
1169 }
1170
1171
1172 OnResize(mBounds);
1173 if (aRepaint)
1174 Update();
1175 return NS_OK;
1176 }
1177
1178 //-------------------------------------------------------------------------
1179 //
1180 // Resize this component
1181 //
1182 //-------------------------------------------------------------------------
1183 NS_METHOD nsWindow::Resize(PRInt32 aX,
1184 PRInt32 aY,
1185 PRInt32 aWidth,
1186 PRInt32 aHeight,
1187 PRBool aRepaint)
1188 {
1189 Move(aX,aY);
1190 Resize(aWidth,aHeight,aRepaint);
1191 return NS_OK;
1192 }
1193
1194 NS_METHOD nsWindow::SetModal(PRBool aModal)
1195 {
1196 if(!(mView && mView->Window()))
1197 return NS_ERROR_FAILURE;
1198 if(aModal)
1199 {
1200 window_feel newfeel;
1201 switch(mBWindowFeel)
1202 {
1203 case B_FLOATING_SUBSET_WINDOW_FEEL:
1204 newfeel = B_MODAL_SUBSET_WINDOW_FEEL;
1205 break;
1206 case B_FLOATING_APP_WINDOW_FEEL:
1207 newfeel = B_MODAL_APP_WINDOW_FEEL;
1208 break;
1209 case B_FLOATING_ALL_WINDOW_FEEL:
1210 newfeel = B_MODAL_ALL_WINDOW_FEEL;
1211 break;
1212 default:
1213 return NS_OK;
1214 }
1215 mView->Window()->SetFeel(newfeel);
1216 }
1217 else
1218 {
1219 mView->Window()->SetFeel(mBWindowFeel);
1220 }
1221 return NS_OK;
1222 }
1223 //-------------------------------------------------------------------------
1224 //
1225 // Enable/disable this component
1226 //
1227 //-------------------------------------------------------------------------
1228 NS_METHOD nsWindow::Enable(PRBool aState)
1229 {
1230 //TODO: Needs real corect implementation in future
1231 mEnabled = aState;
1232 return NS_OK;
1233 }
1234
1235
1236 NS_METHOD nsWindow::IsEnabled(PRBool *aState)
1237 {
1238 NS_ENSURE_ARG_POINTER(aState);
1239 // looks easy enough, but...
1240 *aState = mEnabled;
1241 return NS_OK;
1242 }
1243
1244 //-------------------------------------------------------------------------
1245 //
1246 // Give the focus to this component
1247 //
1248 //-------------------------------------------------------------------------
1249 NS_METHOD nsWindow::SetFocus(PRBool aRaise)
1250 {
1251 //
1252 // Switch to the "main gui thread" if necessary... This method must
1253 // be executed on the "gui thread"...
1254 //
1255 nsToolkit* toolkit = (nsToolkit *)mToolkit;
1256 if (!toolkit->IsGuiThread())
1257 {
1258 uint32 args[1];
1259 args[0] = (uint32)aRaise;
1260 MethodInfo info(this, this, nsSwitchToUIThread::SET_FOCUS, 1, args);
1261 toolkit->CallMethod(&info);
1262 return NS_ERROR_FAILURE;
1263 }
1264
1265 // Don't set focus on disabled widgets or popups
1266 if (!mEnabled || eWindowType_popup == mWindowType)
1267 return NS_OK;
1268
1269 if (mView && mView->LockLooper())
1270 {
1271 if (mView->Window() &&
1272 aRaise == PR_TRUE &&
1273 eWindowType_popup != mWindowType &&
1274 !mView->Window()->IsActive() &&
1275 gLastActiveWindow != mView->Window())
1276 mView->Window()->Activate(true);
1277
1278 mView->MakeFocus(true);
1279 mView->UnlockLooper();
1280 DispatchFocus(NS_GOTFOCUS);
1281 }
1282
1283 return NS_OK;
1284 }
1285
1286 //-------------------------------------------------------------------------
1287 //
1288 // Get this component size and position in screen coordinates
1289 //
1290 //-------------------------------------------------------------------------
1291 NS_IMETHODIMP nsWindow::GetScreenBounds(nsRect &aRect)
1292 {
1293 // A window's Frame() value is cached, so locking is not needed
1294 if (mView && mView->Window())
1295 {
1296 BRect r = mView->Window()->Frame();
1297 aRect.x = nscoord(r.left);
1298 aRect.y = nscoord(r.top);
1299 aRect.width = r.IntegerWidth()+1;
1300 aRect.height = r.IntegerHeight()+1;
1301 }
1302 else
1303 {
1304 aRect = mBounds;
1305 }
1306 return NS_OK;
1307 }
1308
1309 //-------------------------------------------------------------------------
1310 //
1311 // Set the background/foreground color
1312 //
1313 //-------------------------------------------------------------------------
1314 NS_METHOD nsWindow::SetBackgroundColor(const nscolor &aColor)
1315 {
1316 nsBaseWidget::SetBackgroundColor(aColor);
1317
1318 // We set the background of toplevel windows so that resizing doesn't show thru
1319 // to Desktop and resizing artifacts. Child windows has transparent background.
1320 if (!mIsTopWidgetWindow)
1321 return NS_OK;
1322
1323 if (mView && mView->LockLooper())
1324 {
1325 mView->SetViewColor(NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor), NS_GET_A(aColor));
1326 mView->UnlockLooper();
1327 }
1328 return NS_OK;
1329 }
1330
1331 //-------------------------------------------------------------------------
1332 //
1333 // Get this component font
1334 //
1335 //-------------------------------------------------------------------------
1336 nsIFontMetrics* nsWindow::GetFont(void)
1337 {
1338 return mFontMetrics;
1339 }
1340
1341
1342 //-------------------------------------------------------------------------
1343 //
1344 // Set this component font
1345 //
1346 //-------------------------------------------------------------------------
1347 NS_METHOD nsWindow::SetFont(const nsFont &aFont)
1348 {
1349 // Cache Font for owner draw
1350 NS_IF_RELEASE(mFontMetrics);
1351 if (mContext)
1352 mContext->GetMetricsFor(aFont, mFontMetrics);
1353 return NS_OK;
1354 }
1355
1356
1357 //-------------------------------------------------------------------------
1358 //
1359 // Set this component cursor
1360 //
1361 //-------------------------------------------------------------------------
1362
1363 NS_METHOD nsWindow::SetCursor(nsCursor aCursor)
1364 {
1365 if (!mView)
1366 return NS_ERROR_FAILURE;
1367
1368 // mCursor isn't always right. Scrollbars and others change it, too.
1369 // If we want this optimization we need a better way to do it.
1370 // See bug 403406 for more information.
1371 // if (aCursor != mCursor)
1372 // {
1373 BCursor const *newCursor = B_CURSOR_SYSTEM_DEFAULT;
1374
1375 // Check to see if the array has been loaded, if not, do it.
1376 if (gCursorArray.Count() == 0)
1377 {
1378 gCursorArray.InsertElementAt((void*) new BCursor(cursorHyperlink),0);
1379 gCursorArray.InsertElementAt((void*) new BCursor(cursorHorizontalDrag),1);
1380 gCursorArray.InsertElementAt((void*) new BCursor(cursorVerticalDrag),2);
1381 gCursorArray.InsertElementAt((void*) new BCursor(cursorUpperLeft),3);
1382 gCursorArray.InsertElementAt((void*) new BCursor(cursorLowerRight),4);
1383 gCursorArray.InsertElementAt((void*) new BCursor(cursorUpperRight),5);
1384 gCursorArray.InsertElementAt((void*) new BCursor(cursorLowerLeft),6);
1385 gCursorArray.InsertElementAt((void*) new BCursor(cursorCrosshair),7);
1386 gCursorArray.InsertElementAt((void*) new BCursor(cursorHelp),8);
1387 gCursorArray.InsertElementAt((void*) new BCursor(cursorGrab),9);
1388 gCursorArray.InsertElementAt((void*) new BCursor(cursorGrabbing),10);
1389 gCursorArray.InsertElementAt((void*) new BCursor(cursorCopy),11);
1390 gCursorArray.InsertElementAt((void*) new BCursor(cursorAlias),12);
1391 gCursorArray.InsertElementAt((void*) new BCursor(cursorWatch2),13);
1392 gCursorArray.InsertElementAt((void*) new BCursor(cursorCell),14);
1393 gCursorArray.InsertElementAt((void*) new BCursor(cursorZoomIn),15);
1394 gCursorArray.InsertElementAt((void*) new BCursor(cursorZoomOut),16);
1395 gCursorArray.InsertElementAt((void*) new BCursor(cursorLeft),17);
1396 gCursorArray.InsertElementAt((void*) new BCursor(cursorRight),18);
1397 gCursorArray.InsertElementAt((void*) new BCursor(cursorTop),19);
1398 gCursorArray.InsertElementAt((void*) new BCursor(cursorBottom),20);
1399 }
1400
1401 switch (aCursor)
1402 {
1403 case eCursor_standard:
1404 case eCursor_move:
1405 newCursor = B_CURSOR_SYSTEM_DEFAULT;
1406 break;
1407
1408 case eCursor_select:
1409 newCursor = B_CURSOR_I_BEAM;
1410 break;
1411
1412 case eCursor_hyperlink:
1413 newCursor = (BCursor *)gCursorArray.SafeElementAt(0);
1414 break;
1415
1416 case eCursor_n_resize:
1417 newCursor = (BCursor *)gCursorArray.SafeElementAt(19);
1418 break;
1419
1420 case eCursor_s_resize:
1421 newCursor = (BCursor *)gCursorArray.SafeElementAt(20);
1422 break;
1423
1424 case eCursor_w_resize:
1425 newCursor = (BCursor *)gCursorArray.SafeElementAt(17);
1426 break;
1427
1428 case eCursor_e_resize:
1429 newCursor = (BCursor *)gCursorArray.SafeElementAt(18);
1430 break;
1431
1432 case eCursor_nw_resize:
1433 newCursor = (BCursor *)gCursorArray.SafeElementAt(3);
1434 break;
1435
1436 case eCursor_se_resize:
1437 newCursor = (BCursor *)gCursorArray.SafeElementAt(4);
1438 break;
1439
1440 case eCursor_ne_resize:
1441 newCursor = (BCursor *)gCursorArray.SafeElementAt(5);
1442 break;
1443
1444 case eCursor_sw_resize:
1445 newCursor = (BCursor *)gCursorArray.SafeElementAt(6);
1446 break;
1447
1448 case eCursor_crosshair:
1449 newCursor = (BCursor *)gCursorArray.SafeElementAt(7);
1450 break;
1451
1452 case eCursor_help:
1453 newCursor = (BCursor *)gCursorArray.SafeElementAt(8);
1454 break;
1455
1456 case eCursor_copy:
1457 newCursor = (BCursor *)gCursorArray.SafeElementAt(11);
1458 break;
1459
1460 case eCursor_alias:
1461 newCursor = (BCursor *)gCursorArray.SafeElementAt(12);
1462 break;
1463
1464 case eCursor_context_menu:
1465 // XXX: No suitable cursor, needs implementing
1466 break;
1467
1468 case eCursor_cell:
1469 newCursor = (BCursor *)gCursorArray.SafeElementAt(14);
1470 break;
1471
1472 case eCursor_grab:
1473 newCursor = (BCursor *)gCursorArray.SafeElementAt(9);
1474 break;
1475
1476 case eCursor_grabbing:
1477 newCursor = (BCursor *)gCursorArray.SafeElementAt(10);
1478 break;
1479
1480 case eCursor_wait:
1481 case eCursor_spinning:
1482 newCursor = (BCursor *)gCursorArray.SafeElementAt(13);
1483 break;
1484
1485 case eCursor_zoom_in:
1486 newCursor = (BCursor *)gCursorArray.SafeElementAt(15);
1487 break;
1488
1489 case eCursor_zoom_out:
1490 newCursor = (BCursor *)gCursorArray.SafeElementAt(16);
1491 break;
1492
1493 case eCursor_not_allowed:
1494 case eCursor_no_drop:
1495 // XXX: No suitable cursor, needs implementing
1496 break;
1497
1498 case eCursor_col_resize:
1499 // XXX not 100% appropriate perhaps
1500 newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
1501 break;
1502
1503 case eCursor_row_resize:
1504 // XXX not 100% appropriate perhaps
1505 newCursor = (BCursor *)gCursorArray.SafeElementAt(2);
1506 break;
1507
1508 case eCursor_vertical_text:
1509 // XXX not 100% appropriate perhaps
1510 newCursor = B_CURSOR_I_BEAM;
1511 break;
1512
1513 case eCursor_all_scroll:
1514 // XXX: No suitable cursor, needs implementing
1515 break;
1516
1517 case eCursor_nesw_resize:
1518 // XXX not 100% appropriate perhaps
1519 newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
1520 break;
1521
1522 case eCursor_nwse_resize:
1523 // XXX not 100% appropriate perhaps
1524 newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
1525 break;
1526
1527 case eCursor_ns_resize:
1528 newCursor = (BCursor *)gCursorArray.SafeElementAt(2);
1529 break;
1530
1531 case eCursor_ew_resize:
1532 newCursor = (BCursor *)gCursorArray.SafeElementAt(1);
1533 break;
1534
1535 default:
1536 NS_ASSERTION(0, "Invalid cursor type");
1537 break;
1538 }
1539 NS_ASSERTION(newCursor != nsnull, "Cursor not stored in array properly!");
1540 mCursor = aCursor;
1541 be_app->SetCursor(newCursor, true);
1542 // }
1543 return NS_OK;
1544 }
1545
1546 //-------------------------------------------------------------------------
1547 //
1548 // Invalidate this component visible area
1549 //
1550 //-------------------------------------------------------------------------
1551 NS_METHOD nsWindow::Invalidate(PRBool aIsSynchronous)
1552 {
1553 nsresult rv = NS_ERROR_FAILURE;
1554 // Asynchronous painting is performed with via nsViewBeOS::Draw() call and its message queue.
1555 // All update rects are collected in nsViewBeOS member "paintregion".
1556 // Flushing of paintregion happens in nsViewBeOS::GetPaintRegion(),
1557 // cleanup - in nsViewBeOS::Validate(), called in OnPaint().
1558 BRegion reg;
1559 reg.MakeEmpty();
1560 if (mView && mView->LockLooper())
1561 {
1562 if (PR_TRUE == aIsSynchronous)
1563 {
1564 mView->paintregion.Include(mView->Bounds());
1565 reg.Include(mView->Bounds());
1566 }
1567 else
1568 {
1569 mView->Draw(mView->Bounds());
1570 rv = NS_OK;
1571 }
1572 mView->UnlockLooper();
1573 }
1574 // Instant repaint.
1575 if (PR_TRUE == aIsSynchronous)
1576 rv = OnPaint(®);
1577 return rv;
1578 }
1579
1580 //-------------------------------------------------------------------------
1581 //
1582 // Invalidate this component visible area
1583 //
1584 //-------------------------------------------------------------------------
1585 NS_METHOD nsWindow::Invalidate(const nsRect & aRect, PRBool aIsSynchronous)
1586 {
1587 nsresult rv = NS_ERROR_FAILURE;
1588 // Very temporary region for double accounting.
1589 BRegion reg;
1590 reg.MakeEmpty();
1591 if (mView && mView->LockLooper())
1592 {
1593 BRect r(aRect.x,
1594 aRect.y,
1595 aRect.x + aRect.width - 1,
1596 aRect.y + aRect.height - 1);
1597 if (PR_TRUE == aIsSynchronous)
1598 {
1599 mView->paintregion.Include(r);
1600 reg.Include(r);
1601 }
1602 else
1603 {
1604 // we use Draw() instead direct addition to paintregion,
1605 // as it sets queue of notification messages for painting.
1606 mView->Draw(r);
1607 rv = NS_OK;
1608 }
1609 mView->UnlockLooper();
1610 }
1611 // Instant repaint - for given rect only.
1612 // Don't repaint area which isn't marked here for synchronous repaint explicitly.
1613 // BRegion "reg" (equal to aRect) will be substracted from paintregion in OnPaint().
1614 if (PR_TRUE == aIsSynchronous)
1615 rv = OnPaint(®);
1616 return rv;
1617 }
1618
1619 //-------------------------------------------------------------------------
1620 //
1621 // Invalidate this component visible area
1622 //
1623 //-------------------------------------------------------------------------
1624 NS_IMETHODIMP nsWindow::InvalidateRegion(const nsIRegion *aRegion, PRBool aIsSynchronous)
1625 {
1626
1627 nsRegionRectSet *rectSet = nsnull;
1628 if (!aRegion)
1629 return NS_ERROR_FAILURE;
1630 nsresult rv = ((nsIRegion *)aRegion)->GetRects(&rectSet);
1631 if (NS_FAILED(rv))
1632 return rv;
1633 BRegion reg;
1634 reg.MakeEmpty();
1635 if (mView && mView->LockLooper())
1636 {
1637 for (PRUint32 i=0; i< rectSet->mRectsLen; ++i)
1638 {
1639 BRect br(rectSet->mRects[i].x, rectSet->mRects[i].y,
1640 rectSet->mRects[i].x + rectSet->mRects[i].width-1,
1641 rectSet->mRects[i].y + rectSet->mRects[i].height -1);
1642 if (PR_TRUE == aIsSynchronous)
1643 {
1644 mView->paintregion.Include(br);
1645 reg.Include(br);
1646 }
1647 else
1648 {
1649 mView->Draw(br);
1650 rv = NS_OK;
1651 }
1652 }
1653 mView->UnlockLooper();
1654 }
1655 // Instant repaint - for given region only.
1656 // BRegion "reg"(equal to aRegion) will be substracted from paintregion in OnPaint().
1657 if (PR_TRUE == aIsSynchronous)
1658 rv = OnPaint(®);
1659
1660 return rv;
1661 }
1662
1663 //-------------------------------------------------------------------------
1664 //
1665 // Force a synchronous repaint of the window
1666 //
1667 //-------------------------------------------------------------------------
1668 NS_IMETHODIMP nsWindow::Update()
1669 {
1670 nsresult rv = NS_ERROR_FAILURE;
1671 //Switching scrolling trigger off
1672 mIsScrolling = PR_FALSE;
1673 if (mWindowType == eWindowType_child)
1674 return NS_OK;
1675 // Getting whole paint cache filled in native and non-native Invalidate() calls.
1676 // Sending it all to view manager via OnPaint()
1677 BRegion reg;
1678 reg.MakeEmpty();
1679 if(mView && mView->LockLooper())
1680 {
1681 //Flushing native pending updates*/
1682 if (mView->Window())
1683 mView->Window()->UpdateIfNeeded();
1684 bool nonempty = mView->GetPaintRegion(®);
1685 mView->UnlockLooper();
1686 if (nonempty)
1687 rv = OnPaint(®);
1688 }
1689 return rv;
1690 }
1691
1692 //-------------------------------------------------------------------------
1693 //
1694 // Return some native data according to aDataType
1695 //
1696 //-------------------------------------------------------------------------
1697 void* nsWindow::GetNativeData(PRUint32 aDataType)
1698 {
1699 if (!mView)
1700 return NULL;
1701 switch(aDataType)
1702 {
1703 case NS_NATIVE_WINDOW:
1704 return (void *)(mView->Window());
1705 case NS_NATIVE_WIDGET:
1706 case NS_NATIVE_PLUGIN_PORT:
1707 return (void *)((nsViewBeOS *)mView);
1708 case NS_NATIVE_GRAPHIC:
1709 return (void *)((BView *)mView);
1710 case NS_NATIVE_COLORMAP:
1711 default:
1712 break;
1713 }
1714 return NULL;
1715 }
1716
1717 //-------------------------------------------------------------------------
1718 //
1719 // Set the colormap of the window
1720 //
1721 //-------------------------------------------------------------------------
1722 NS_METHOD nsWindow::SetColorMap(nsColorMap *aColorMap)
1723 {
1724 NS_WARNING("nsWindow::SetColorMap - not implemented");
1725 return NS_OK;
1726 }
1727
1728
1729 //-------------------------------------------------------------------------
1730 //
1731 // Scroll the bits of a window
1732 //
1733 //-------------------------------------------------------------------------
1734 NS_METHOD nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsRect *aClipRect)
1735 {
1736 // Switching trigger on
1737 mIsScrolling = PR_TRUE;
1738 //Preventing main view invalidation loop-chain when children are moving
1739 //by by hiding children nsWidgets.
1740 //Maybe this method must be used wider, in move and resize chains
1741 // and implemented in BeginResizingChildren or in Reset*Visibility() methods
1742 //Children will be unhidden in ::Update() when called by other than gkview::Scroll() method.
1743 HideKids(PR_TRUE);
1744 if (mView && mView->LockLooper())
1745 {
1746 // Kill any attempt to invalidate until scroll is finished
1747 mView->SetVisible(false);
1748
1749 BRect src;
1750 BRect b = mView->Bounds();
1751
1752 if (aClipRect)
1753 {
1754 src.left = aClipRect->x;
1755 src.top = aClipRect->y;
1756 src.right = aClipRect->XMost() - 1;
1757 src.bottom = aClipRect->YMost() - 1;
1758 }
1759 else
1760 {
1761 src = b;
1762 }
1763 // Restricting source by on-screen part of BView
1764 if (mView->Window())
1765 {
1766 BRect screenframe = mView->ConvertFromScreen(BScreen(mView->Window()).Frame());
1767 src = src & screenframe;
1768 if (mView->Parent())
1769 {
1770 BRect parentframe = mView->ConvertFromParent(mView->Parent()->Frame());
1771 src = src & parentframe;
1772 }
1773 }
1774
1775 BRegion invalid;
1776 invalid.Include(src);
1777 // Next source clipping check, for same level siblings
1778 if ( BView *v = mView->Parent() )
1779 {
1780 for (BView *child = v->ChildAt(0); child; child = child->NextSibling() )
1781 {
1782 BRect siblingframe = mView->ConvertFromParent(child->Frame());
1783 if (child != mView && child->Parent() != mView)
1784 {
1785 invalid.Exclude(siblingframe);
1786 mView->paintregion.Exclude(siblingframe);
1787 }
1788 }
1789 src = invalid.Frame();
1790 }
1791
1792 // make sure we only reference visible bits
1793 // so we don't trigger a BView invalidate
1794
1795 if (src.left + aDx < 0)
1796 src.left = -aDx;
1797 if (src.right + aDx > b.right)
1798 src.right = b.right - aDx;
1799 if (src.top + aDy < 0)
1800 src.top = -aDy;
1801 if (src.bottom + aDy > b.bottom)
1802 src.bottom = b.bottom - aDy;
1803
1804 BRect dest = src.OffsetByCopy(aDx, aDy);
1805 mView->ConstrainClippingRegion(&invalid);
1806 // Moving visible content
1807 if (src.IsValid() && dest.IsValid())
1808 mView->CopyBits(src, dest);
1809
1810 invalid.Exclude(dest);
1811 // Native paintregion needs shifting too, it is very important action
1812 // (as app_server doesn't know about Mozilla viewmanager tricks) -
1813 // it allows proper update after scroll for areas covered by other windows.
1814 mView->paintregion.OffsetBy(aDx, aDy);
1815 mView->ConstrainClippingRegion(&invalid);
1816 // Time to silently move now invisible children
1817 for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling())
1818 {
1819 nsWindow *childWidget = NS_STATIC_CAST(nsWindow*, kid);
1820 // No need to Lock/UnlockLooper with GetBounds() and Move() methods
1821 // using cached values and native MoveBy() instead
1822 nsRect bounds = childWidget->mBounds;
1823 bounds.x += aDx;
1824 bounds.y += aDy;
1825 childWidget->Move(bounds.x, bounds.y);
1826 BView *child = ((BView *)kid->GetNativeData(NS_NATIVE_WIDGET));
1827 if (child)
1828 {
1829 //There is native child
1830 mView->paintregion.Exclude(child->Frame());
1831 }
1832 }
1833
1834 // Painting calculated region now,
1835 // letting Update() to paint remaining content of paintregion
1836 OnPaint(&invalid);
1837 HideKids(PR_FALSE);
1838 // re-allow updates
1839 mView->SetVisible(true);
1840 mView->UnlockLooper();
1841
1842 }
1843 return NS_OK;
1844 }
1845
1846
1847 //-------------------------------------------------------------------------
1848 //
1849 // Every function that needs a thread switch goes through this function
1850 // by calling SendMessage (..WM_CALLMETHOD..) in nsToolkit::CallMethod.
1851 //
1852 //-------------------------------------------------------------------------
1853 bool nsWindow::CallMethod(MethodInfo *info)
1854 {
1855 bool bRet = TRUE;
1856
1857 switch (info->methodId)
1858 {
1859 case nsSwitchToUIThread::CREATE:
1860 NS_ASSERTION(info->nArgs == 7, "Wrong number of arguments to CallMethod");
1861 Create((nsIWidget*)(info->args[0]),
1862 (nsRect&)*(nsRect*)(info->args[1]),
1863 (EVENT_CALLBACK)(info->args[2]),
1864 (nsIDeviceContext*)(info->args[3]),
1865 (nsIAppShell *)(info->args[4]),
1866 (nsIToolkit*)(info->args[5]),
1867 (nsWidgetInitData*)(info->args[6]));
1868 break;
1869
1870 case nsSwitchToUIThread::CREATE_NATIVE:
1871 NS_ASSERTION(info->nArgs == 7, "Wrong number of arguments to CallMethod");
1872 Create((nsNativeWidget)(info->args[0]),
1873 (nsRect&)*(nsRect*)(info->args[1]),
1874 (EVENT_CALLBACK)(info->args[2]),
1875 (nsIDeviceContext*)(info->args[3]),
1876 (nsIAppShell *)(info->args[4]),
1877 (nsIToolkit*)(info->args[5]),
1878 (nsWidgetInitData*)(info->args[6]));
1879 break;
1880
1881 case nsSwitchToUIThread::DESTROY:
1882 NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod");
1883 Destroy();
1884 break;
1885
1886 case nsSwitchToUIThread::CLOSEWINDOW :
1887 {
1888 NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod");
1889 if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
1890 DealWithPopups(nsSwitchToUIThread::CLOSEWINDOW,nsPoint(0,0));
1891 for (nsIWidget* kid = mFirstChild; kid; kid = kid->GetNextSibling())
1892 {
1893 nsWindow *childWidget = NS_STATIC_CAST(nsWindow*, kid);
1894 BWindow* kidwindow = (BWindow *)kid->GetNativeData(NS_NATIVE_WINDOW);
1895 if (kidwindow)
1896 {
1897 // PostMessage() is unsafe, so using BMessenger
1898 BMessenger bm(kidwindow);
1899 bm.SendMessage(B_QUIT_REQUESTED);
1900 }
1901 }
1902 DispatchStandardEvent(NS_DESTROY);
1903 }
1904 break;
1905
1906 case nsSwitchToUIThread::SET_FOCUS:
1907 NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
1908 if (!mEnabled)
1909 return false;
1910 SetFocus(((PRBool *)info->args)[0]);
1911 break;
1912
1913 #ifdef DEBUG_FOCUS
1914 case nsSwitchToUIThread::GOT_FOCUS:
1915 NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
1916 if (!mEnabled)
1917 return false;
1918 if ((uint32)info->args[0] != (uint32)mView)
1919 printf("Wrong view to get focus\n");*/
1920 break;
1921 #endif
1922 case nsSwitchToUIThread::KILL_FOCUS:
1923 NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
1924 if ((uint32)info->args[0] == (uint32)mView)
1925 DispatchFocus(NS_LOSTFOCUS);
1926 #ifdef DEBUG_FOCUS
1927 else
1928 printf("Wrong view to de-focus\n");
1929 #endif
1930 #if defined(BeIME)
1931 nsIMEBeOS::GetIME()->DispatchCancelIME();
1932 if (mView && mView->LockLooper())
1933 {
1934 mView->SetFlags(mView->Flags() & ~B_NAVIGABLE);
1935 mView->UnlockLooper();
1936 }
1937 #endif
1938 break;
1939
1940 case nsSwitchToUIThread::BTNCLICK :
1941 {
1942 NS_ASSERTION(info->nArgs == 5, "Wrong number of arguments to CallMethod");
1943 if (!mEnabled)
1944 return false;
1945 // close popup when clicked outside of the popup window
1946 uint32 eventID = ((int32 *)info->args)[0];
1947 PRBool rollup = PR_FALSE;
1948
1949 if ((eventID == NS_MOUSE_LEFT_BUTTON_DOWN ||
1950 eventID == NS_MOUSE_RIGHT_BUTTON_DOWN ||
1951 eventID == NS_MOUSE_MIDDLE_BUTTON_DOWN) &&
1952 mView && mView->LockLooper())
1953 {
1954 BPoint p(((int32 *)info->args)[1], ((int32 *)info->args)[2]);
1955 mView->ConvertToScreen(&p);
1956 rollup = DealWithPopups(nsSwitchToUIThread::ONMOUSE, nsPoint(p.x, p.y));
1957 mView->UnlockLooper();
1958 }
1959 // Drop click event - bug 314330
1960 if (rollup)
1961 return false;
1962 DispatchMouseEvent(((int32 *)info->args)[0],
1963 nsPoint(((int32 *)info->args)[1], ((int32 *)info->args)[2]),
1964 ((int32 *)info->args)[3],
1965 ((int32 *)info->args)[4]);
1966
1967 if (((int32 *)info->args)[0] == NS_MOUSE_RIGHT_BUTTON_DOWN)
1968 {
1969 DispatchMouseEvent (NS_CONTEXTMENU,
1970 nsPoint(((int32 *)info->args)[1], ((int32 *)info->args)[2]),
1971 ((int32 *)info->args)[3],
1972 ((int32 *)info->args)[4]);
1973 }
1974 }
1975 break;
1976
1977 case nsSwitchToUIThread::ONWHEEL :
1978 {
1979 NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
1980 // avoid mistargeting
1981 if ((uint32)info->args[0] != (uint32)mView)
1982 return false;
1983 BPoint cursor(0,0);
1984 uint32 buttons;
1985 BPoint delta;
1986 if (mView && mView->LockLooper())
1987 {
1988 mView->GetMouse(&cursor, &buttons, false);
1989 delta = mView->GetWheel();
1990 mView->UnlockLooper();
1991 }
1992 else
1993 return false;
1994 // BeOS TwoWheel input-filter is bit buggy atm, generating sometimes X-wheel with no reason,
1995 // so we're setting priority for Y-wheel.
1996 // Also hardcoding here _system_ scroll-step value to 3 lines.
1997 if (nscoord(delta.y) != 0)
1998 {
1999 OnWheel(nsMouseScrollEvent::kIsVertical, buttons, cursor, nscoord(delta.y)*3);
2000 }
2001 else if(nscoord(delta.x) != 0)
2002 OnWheel(nsMouseScrollEvent::kIsHorizontal, buttons, cursor, nscoord(delta.x)*3);
2003 }
2004 break;
2005
2006 case nsSwitchToUIThread::ONKEY :
2007 NS_ASSERTION(info->nArgs == 6, "Wrong number of arguments to CallMethod");
2008 if (((int32 *)info->args)[0] == NS_KEY_DOWN)
2009 {
2010 OnKeyDown(((int32 *)info->args)[0],
2011 (const char *)(&((uint32 *)info->args)[1]), ((int32 *)info->args)[2],
2012 ((uint32 *)info->args)[3], ((uint32 *)info->args)[4], ((int32 *)info->args)[5]);
2013 }
2014 else
2015 {
2016 if (((int32 *)info->args)[0] == NS_KEY_UP)
2017 {
2018 OnKeyUp(((int32 *)info->args)[0],
2019 (const char *)(&((uint32 *)info->args)[1]), ((int32 *)info->args)[2],
2020 ((uint32 *)info->args)[3], ((uint32 *)info->args)[4], ((int32 *)info->args)[5]);
2021 }
2022 }
2023 break;
2024
2025 case nsSwitchToUIThread::ONPAINT :
2026 NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
2027 {
2028 if ((uint32)mView != ((uint32 *)info->args)[0])
2029 return false;
2030 BRegion reg;
2031 reg.MakeEmpty();
2032 if(mView && mView->LockLooper())
2033 {
2034 bool nonempty = mView->GetPaintRegion(®);
2035 mView->UnlockLooper();
2036 if (nonempty)
2037 OnPaint(®);
2038 }
2039 }
2040 break;
2041
2042 case nsSwitchToUIThread::ONRESIZE :
2043 {
2044 NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod");
2045 if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
2046 DealWithPopups(nsSwitchToUIThread::ONRESIZE,nsPoint(0,0));
2047 // This should be called only from BWindow::FrameResized()
2048 if (!mIsTopWidgetWindow || !mView || !mView->Window())
2049 return false;
2050
2051 nsRect r(mBounds);
2052 if (mView->LockLooper())
2053 {
2054 BRect br = mView->Frame();
2055 r.x = nscoord(br.left);
2056 r.y = nscoord(br.top);
2057 r.width = br.IntegerWidth() + 1;
2058 r.height = br.IntegerHeight() + 1;
2059 ((nsWindowBeOS *)mView->Window())->fJustGotBounds = true;
2060 mView->UnlockLooper();
2061 }
2062
2063 OnResize(r);
2064 }
2065 break;
2066
2067 case nsSwitchToUIThread::ONMOUSE :
2068 {
2069 NS_ASSERTION(info->nArgs == 1, "Wrong number of arguments to CallMethod");
2070 if (!mEnabled)
2071 return false;
2072 BPoint cursor(0,0);
2073 uint32 buttons;
2074
2075 if(mView && mView->LockLooper())
2076 {
2077 mView->GetMouse(&cursor, &buttons, true);
2078 mView->UnlockLooper();
2079 }
2080
2081 DispatchMouseEvent(((int32 *)info->args)[0],
2082 nsPoint(int32(cursor.x), int32(cursor.y)),
2083 0,
2084 modifiers());
2085 }
2086 break;
2087
2088 case nsSwitchToUIThread::ONDROP :
2089 {
2090 NS_ASSERTION(info->nArgs == 4, "Wrong number of arguments to CallMethod");
2091
2092 nsMouseEvent event(PR_TRUE, (int32) info->args[0], this, nsMouseEvent::eReal);
2093 nsPoint point(((int32 *)info->args)[1], ((int32 *)info->args)[2]);
2094 InitEvent (event, &point);
2095 uint32 mod = (uint32) info->args[3];
2096 event.isShift = mod & B_SHIFT_KEY;
2097 event.isControl = mod & B_CONTROL_KEY;
2098 event.isAlt = mod & B_COMMAND_KEY;
2099 event.isMeta = mod & B_OPTION_KEY;
2100
2101 // Setting drag action, must be done before event dispatch
2102 nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
2103 if (dragService)
2104 {
2105 nsCOMPtr<nsIDragSession> dragSession;
2106 dragService->GetCurrentSession(getter_AddRefs(dragSession));
2107 if (dragSession)
2108 {
2109 // Original action mask stored in dragsession.
2110 // For native events such mask must be set in nsDragServiceBeOS::UpdateDragMessageIfNeeded()
2111
2112 PRUint32 action_mask = 0;
2113 dragSession->GetDragAction(&action_mask);
2114 PRUint32 action = nsIDragService::DRAGDROP_ACTION_MOVE;
2115 if (mod & B_OPTION_KEY)
2116 {
2117 if (mod & B_COMMAND_KEY)
2118 action = nsIDragService::DRAGDROP_ACTION_LINK & action_mask;
2119 else
2120 action = nsIDragService::DRAGDROP_ACTION_COPY & action_mask;
2121 }
2122 dragSession->SetDragAction(action);
2123 }
2124 }
2125
2126 DispatchWindowEvent(&event);
2127 NS_RELEASE(event.widget);
2128
2129 if (dragService)
2130 dragService->EndDragSession();
2131
2132 }
2133 break;
2134
2135 case nsSwitchToUIThread::ONACTIVATE:
2136 NS_ASSERTION(info->nArgs == 2, "Wrong number of arguments to CallMethod");
2137 if (!mEnabled || eWindowType_popup == mWindowType || 0 == mView->Window())
2138 return false;
2139 if ((BWindow *)info->args[1] != mView->Window())
2140 return false;
2141 if (mEventCallback || eWindowType_child == mWindowType )
2142 {
2143 bool active = (bool)info->args[0];
2144 if (!active)
2145 {
2146 if (eWindowType_dialog == mWindowType ||
2147 eWindowType_toplevel == mWindowType)
2148 DealWithPopups(nsSwitchToUIThread::ONACTIVATE,nsPoint(0,0));
2149 //Testing if BWindow is really deactivated.
2150 if (!mView->Window()->IsActive())
2151 {
2152 // BeOS is poor in windows hierarchy and variations support. In lot of aspects.
2153 // Here is workaround for flacky Activate() handling for B_FLOATING windows.
2154 // We should force parent (de)activation to allow main window to regain control after closing floating dialog.
2155 if (mWindowParent && mView->Window()->IsFloating())
2156 mWindowParent->DispatchFocus(NS_ACTIVATE);
2157
2158 DispatchFocus(NS_DEACTIVATE);
2159 #if defined(BeIME)
2160 nsIMEBeOS::GetIME()->DispatchCancelIME();
2161 #endif
2162 }
2163 }
2164 else
2165 {
2166
2167 if (mView->Window()->IsActive())
2168 {
2169 // See comment above.
2170 if (mWindowParent && mView->Window()->IsFloating())
2171 mWindowParent->DispatchFocus(NS_DEACTIVATE);
2172
2173 DispatchFocus(NS_ACTIVATE);
2174 if (mView && mView->Window())
2175 gLastActiveWindow = mView->Window();
2176 }
2177 }
2178 }
2179 break;
2180
2181 case nsSwitchToUIThread::ONMOVE:
2182 {
2183 NS_ASSERTION(info->nArgs == 0, "Wrong number of arguments to CallMethod");
2184 nsRect r;
2185 // We use this only for tracking whole window moves
2186 GetScreenBounds(r);
2187 if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
2188 DealWithPopups(nsSwitchToUIThread::ONMOVE,nsPoint(0,0));
2189 OnMove(r.x, r.y);
2190 }
2191 break;
2192
2193 case nsSwitchToUIThread::ONWORKSPACE:
2194 {
2195 NS_ASSERTION(info->nArgs == 2, "Wrong number of arguments to CallMethod");
2196 if (eWindowType_popup != mWindowType && eWindowType_child != mWindowType)
2197 DealWithPopups(nsSwitchToUIThread::ONWORKSPACE,nsPoint(0,0));
2198 }
2199 break;
2200
2201 #if defined(BeIME)
2202 case nsSwitchToUIThread::ONIME:
2203 //No assertion used, as number of arguments varies here
2204 if (mView && mView->LockLooper())
2205 {
2206 mView->SetFlags(mView->Flags() | B_NAVIGABLE);
2207 mView->UnlockLooper();
2208 }
2209 nsIMEBeOS::GetIME()->RunIME(info->args, this, mView);
2210 break;
2211 #endif
2212 default:
2213 bRet = FALSE;
2214 break;
2215
2216 }
2217
2218 return bRet;
2219 }
2220
2221 //-------------------------------------------------------------------------
2222 //
2223 // Key code translation related data
2224 //
2225 //-------------------------------------------------------------------------
2226
2227 struct nsKeyConverter {
2228 int vkCode; // Platform independent key code
2229 char bekeycode; // BeOS key code
2230 };
2231
2232 //
2233 // Netscape keycodes are defined in widget/public/nsGUIEvent.h
2234 // BeOS keycodes can be viewd at
2235 // http://www.be.com/documentation/be_book/Keyboard/KeyboardKeyCodes.html
2236 //
2237
2238 struct nsKeyConverter nsKeycodesBeOS[] = {
2239 // { NS_VK_CANCEL, GDK_Cancel },
2240 { NS_VK_BACK, 0x1e },
2241 { NS_VK_TAB, 0x26 },
2242 // { NS_VK_TAB, GDK_ISO_Left_Tab },
2243 // { NS_VK_CLEAR, GDK_Clear },
2244 { NS_VK_RETURN, 0x47 },
2245 { NS_VK_SHIFT, 0x4b },
2246 { NS_VK_SHIFT, 0x56 },
2247 { NS_VK_CONTROL, 0x5c },
2248 { NS_VK_CONTROL, 0x60 },
2249 { NS_VK_ALT, 0x5d },
2250 { NS_VK_ALT, 0x5f },
2251 { NS_VK_PAUSE, 0x22 },
2252 { NS_VK_CAPS_LOCK, 0x3b },
2253 { NS_VK_ESCAPE, 0x1 },
2254 { NS_VK_SPACE, 0x5e },
2255 { NS_VK_PAGE_UP, 0x21 },
2256 { NS_VK_PAGE_DOWN, 0x36 },
2257 { NS_VK_END, 0x35 },
2258 { NS_VK_HOME, 0x20 },
2259 { NS_VK_LEFT, 0x61 },
2260 { NS_VK_UP, 0x57 },
2261 { NS_VK_RIGHT, 0x63 },
2262 { NS_VK_DOWN, 0x62 },
2263 { NS_VK_PRINTSCREEN, 0xe },
2264 { NS_VK_INSERT, 0x1f },
2265 { NS_VK_DELETE, 0x34 },
2266
2267 // The "Windows Key"
2268 { NS_VK_META, 0x66 },
2269 { NS_VK_META, 0x67 },
2270
2271 // keypad keys (constant keys)
2272 { NS_VK_MULTIPLY, 0x24 },
2273 { NS_VK_ADD, 0x3a },
2274 // { NS_VK_SEPARATOR, }, ???
2275 { NS_VK_SUBTRACT, 0x25 },
2276 { NS_VK_DIVIDE, 0x23 },
2277 { NS_VK_RETURN, 0x5b },
2278
2279 { NS_VK_COMMA, 0x53 },
2280 { NS_VK_PERIOD, 0x54 },
2281 { NS_VK_SLASH, 0x55 },
2282 { NS_VK_BACK_SLASH, 0x33 },
2283 { NS_VK_BACK_SLASH, 0x6a }, // got this code on japanese keyboard
2284 { NS_VK_BACK_SLASH, 0x6b }, // got this code on japanese keyboard
2285 { NS_VK_BACK_QUOTE, 0x11 },
2286 { NS_VK_OPEN_BRACKET, 0x31 },
2287 { NS_VK_CLOSE_BRACKET, 0x32 },
2288 { NS_VK_SEMICOLON, 0x45 },
2289 { NS_VK_QUOTE, 0x46 },
2290
2291 // NS doesn't have dash or equals distinct from the numeric keypad ones,
2292 // so we'll use those for now. See bug 17008:
2293 { NS_VK_SUBTRACT, 0x1c },
2294 { NS_VK_EQUALS, 0x1d },
2295
2296 { NS_VK_F1, B_F1_KEY },
2297 { NS_VK_F2, B_F2_KEY },
2298 { NS_VK_F3, B_F3_KEY },
2299 { NS_VK_F4, B_F4_KEY },
2300 { NS_VK_F5, B_F5_KEY },
2301 { NS_VK_F6, B_F6_KEY },
2302 { NS_VK_F7, B_F7_KEY },
2303 { NS_VK_F8, B_F8_KEY },
2304 { NS_VK_F9, B_F9_KEY },
2305 { NS_VK_F10, B_F10_KEY },
2306 { NS_VK_F11, B_F11_KEY },
2307 { NS_VK_F12, B_F12_KEY },
2308
2309 { NS_VK_1, 0x12 },
2310 { NS_VK_2, 0x13 },
2311 { NS_VK_3, 0x14 },
2312 { NS_VK_4, 0x15 },
2313 { NS_VK_5, 0x16 },
2314 { NS_VK_6, 0x17 },
2315 { NS_VK_7, 0x18 },
2316 { NS_VK_8, 0x19 },
2317 { NS_VK_9, 0x1a },
2318 { NS_VK_0, 0x1b },
2319
2320 { NS_VK_A, 0x3c },
2321 { NS_VK_B, 0x50 },
2322 { NS_VK_C, 0x4e },
2323 { NS_VK_D, 0x3e },
2324 { NS_VK_E, 0x29 },
2325 { NS_VK_F, 0x3f },
2326 { NS_VK_G, 0x40 },
2327 { NS_VK_H, 0x41 },
2328 { NS_VK_I, 0x2e },
2329 { NS_VK_J, 0x42 },
2330 { NS_VK_K, 0x43 },
2331 { NS_VK_L, 0x44 },
2332 { NS_VK_M, 0x52 },
2333 { NS_VK_N, 0x51 },
2334 { NS_VK_O, 0x2f },
2335 { NS_VK_P, 0x30 },
2336 { NS_VK_Q, 0x27 },
2337 { NS_VK_R, 0x2a },
2338 { NS_VK_S, 0x3d },
2339 { NS_VK_T, 0x2b },
2340 { NS_VK_U, 0x2d },
2341 { NS_VK_V, 0x4f },
2342 { NS_VK_W, 0x28 },
2343 { NS_VK_X, 0x4d },
2344 { NS_VK_Y, 0x2c },
2345 { NS_VK_Z, 0x4c }
2346 };
2347
2348 // keycode of keypad when num-locked
2349 struct nsKeyConverter nsKeycodesBeOSNumLock[] = {
2350 { NS_VK_NUMPAD0, 0x64 },
2351 { NS_VK_NUMPAD1, 0x58 },
2352 { NS_VK_NUMPAD2, 0x59 },
2353 { NS_VK_NUMPAD3, 0x5a },
2354 { NS_VK_NUMPAD4, 0x48 },
2355 { NS_VK_NUMPAD5, 0x49 },
2356 { NS_VK_NUMPAD6, 0x4a },
2357 { NS_VK_NUMPAD7, 0x37 },
2358 { NS_VK_NUMPAD8, 0x38 },
2359 { NS_VK_NUMPAD9, 0x39 },
2360 { NS_VK_DECIMAL, 0x65 }
2361 };
2362
2363 // keycode of keypad when not num-locked
2364 struct nsKeyConverter nsKeycodesBeOSNoNumLock[] = {
2365 { NS_VK_LEFT, 0x48 },
2366 { NS_VK_RIGHT, 0x4a },
2367 { NS_VK_UP, 0x38 },
2368 { NS_VK_DOWN, 0x59 },
2369 { NS_VK_PAGE_UP, 0x39 },
2370 { NS_VK_PAGE_DOWN, 0x5a },
2371 { NS_VK_HOME, 0x37 },
2372 { NS_VK_END, 0x58 },
2373 { NS_VK_INSERT, 0x64 },
2374 { NS_VK_DELETE, 0x65 }
2375 };
2376
2377 //-------------------------------------------------------------------------
2378 //
2379 // Translate key code
2380 // Input is BeOS keyboard key-code; output is in NS_VK format
2381 //
2382 //-------------------------------------------------------------------------
2383
2384 static int TranslateBeOSKeyCode(int32 bekeycode, bool isnumlock)
2385 {
2386 #ifdef KB_DEBUG
2387 printf("TranslateBeOSKeyCode: bekeycode = 0x%x\n",bekeycode);
2388 #endif
2389 int i;
2390 int length = sizeof(nsKeycodesBeOS) / sizeof(struct nsKeyConverter);
2391 int length_numlock = sizeof(nsKeycodesBeOSNumLock) / sizeof(struct nsKeyConverter);
2392 int length_nonumlock = sizeof(nsKeycodesBeOSNoNumLock) / sizeof(struct nsKeyConverter);
2393
2394 // key code conversion
2395 for (i = 0; i < length; i++) {
2396 if (nsKeycodesBeOS[i].bekeycode == bekeycode)
2397 return(nsKeycodesBeOS[i].vkCode);
2398 }
2399 // numpad keycode vary with numlock
2400 if (isnumlock) {
2401 for (i = 0; i < length_numlock; i++) {
2402 if (nsKeycodesBeOSNumLock[i].bekeycode == bekeycode)
2403 return(nsKeycodesBeOSNumLock[i].vkCode);
2404 }
2405 } else {
2406 for (i = 0; i < length_nonumlock; i++) {
2407 if (nsKeycodesBeOSNoNumLock[i].bekeycode == bekeycode)
2408 return(nsKeycodesBeOSNoNumLock[i].vkCode);
2409 }
2410 }
2411 #ifdef KB_DEBUG
2412 printf("TranslateBeOSKeyCode: ####### Translation not Found #######\n");
2413 #endif
2414 return((int)0);
2415 }
2416
2417 //-------------------------------------------------------------------------
2418 //
2419 // OnKeyDown
2420 //
2421 //-------------------------------------------------------------------------
2422 PRBool nsWindow::OnKeyDown(PRUint32 aEventType, const char *bytes,
2423 int32 numBytes, PRUint32 mod, PRUint32 bekeycode, int32 rawcode)
2424 {
2425 PRUint32 aTranslatedKeyCode;
2426 PRBool noDefault = PR_FALSE;
2427
2428 mIsShiftDown = (mod & B_SHIFT_KEY) ? PR_TRUE : PR_FALSE;
2429 mIsControlDown = (mod & B_CONTROL_KEY) ? PR_TRUE : PR_FALSE;
2430 mIsAltDown = ((mod & B_COMMAND_KEY) && !(mod & B_RIGHT_OPTION_KEY))? PR_TRUE : PR_FALSE;
2431 mIsMetaDown = (mod & B_LEFT_OPTION_KEY) ? PR_TRUE : PR_FALSE;
2432 bool IsNumLocked = ((mod & B_NUM_LOCK) != 0);
2433
2434 aTranslatedKeyCode = TranslateBeOSKeyCode(bekeycode, IsNumLocked);
2435
2436 if (numBytes <= 1)
2437 {
2438 noDefault = DispatchKeyEvent(NS_KEY_DOWN, 0, aTranslatedKeyCode);
2439 } else {
2440 // non ASCII chars
2441 }
2442
2443 // ------------ On Char ------------
2444 PRUint32 uniChar;
2445
2446 if ((mIsControlDown || mIsAltDown || mIsMetaDown) && rawcode >= 'a' && rawcode <= 'z') {
2447 if (mIsShiftDown)
2448 uniChar = rawcode + 'A' - 'a';
2449 else
2450 uniChar = rawcode;
2451 aTranslatedKeyCode = 0;
2452 } else {
2453 if (numBytes == 0) // deal with unmapped key
2454 return noDefault;
2455
2456 switch((unsigned char)bytes[0])
2457 {
2458 case 0xc8://System Request
2459 case 0xca://Break
2460 return noDefault;// do not send 'KEY_PRESS' message
2461
2462 case B_INSERT:
2463 case B_ESCAPE:
2464 case B_FUNCTION_KEY:
2465 case B_HOME:
2466 case B_PAGE_UP:
2467 case B_END:
2468 case B_PAGE_DOWN:
2469 case B_UP_ARROW:
2470 case B_LEFT_ARROW:
2471 case B_DOWN_ARROW:
2472 case B_RIGHT_ARROW:
2473 case B_TAB:
2474 case B_DELETE:
2475 case B_BACKSPACE:
2476 case B_ENTER:
2477 uniChar = 0;
2478 break;
2479
2480 default:
2481 // UTF-8 to unicode conversion
2482 if (numBytes >= 1 && (bytes[0] & 0x80) == 0) {
2483 // 1 byte utf-8 char
2484 uniChar = bytes[0];
2485 } else
2486 if (numBytes >= 2 && (bytes[0] & 0xe0) == 0xc0) {
2487 // 2 byte utf-8 char
2488 uniChar = ((uint16)(bytes[0] & 0x1f) << 6) | (uint16)(bytes[1] & 0x3f);
2489 } else
2490 if (numBytes >= 3 && (bytes[0] & 0xf0) == 0xe0) {
2491 // 3 byte utf-8 char
2492 uniChar = ((uint16)(bytes[0] & 0x0f) << 12) | ((uint16)(bytes[1] & 0x3f) << 6)
2493 | (uint16)(bytes[2] & 0x3f);
2494 } else {
2495 //error
2496 uniChar = 0;
2497 NS_WARNING("nsWindow::OnKeyDown() error: bytes[] has not enough chars.");
2498 }
2499
2500 aTranslatedKeyCode = 0;
2501 break;
2502 }
2503 }
2504
2505 // If prevent default set for onkeydown, do the same for onkeypress
2506 PRUint32 extraFlags = (noDefault ? NS_EVENT_FLAG_NO_DEFAULT : 0);
2507 return DispatchKeyEvent(NS_KEY_PRESS, uniChar, aTranslatedKeyCode, extraFlags) && noDefault;
2508 }
2509
2510 //-------------------------------------------------------------------------
2511 //
2512 // OnKeyUp
2513 //
2514 //-------------------------------------------------------------------------
2515 PRBool nsWindow::OnKeyUp(PRUint32 aEventType, const char *bytes,
2516 int32 numBytes, PRUint32 mod, PRUint32 bekeycode, int32 rawcode)
2517 {
2518 PRUint32 aTranslatedKeyCode;
2519 bool IsNumLocked = ((mod & B_NUM_LOCK) != 0);
2520
2521 mIsShiftDown = (mod & B_SHIFT_KEY) ? PR_TRUE : PR_FALSE;
2522 mIsControlDown = (mod & B_CONTROL_KEY) ? PR_TRUE : PR_FALSE;
2523 mIsAltDown = ((mod & B_COMMAND_KEY) && !(mod & B_RIGHT_OPTION_KEY))? PR_TRUE : PR_FALSE;
2524 mIsMetaDown = (mod & B_LEFT_OPTION_KEY) ? PR_TRUE : PR_FALSE;
2525
2526 aTranslatedKeyCode = TranslateBeOSKeyCode(bekeycode, IsNumLocked);
2527
2528 PRBool result = DispatchKeyEvent(NS_KEY_UP, 0, aTranslatedKeyCode);
2529 return result;
2530
2531 }
2532
2533 //-------------------------------------------------------------------------
2534 //
2535 // DispatchKeyEvent
2536 //
2537 //-------------------------------------------------------------------------
2538
2539 PRBool nsWindow::DispatchKeyEvent(PRUint32 aEventType, PRUint32 aCharCode,
2540 PRUint32 aKeyCode, PRUint32 aFlags)
2541 {
2542 nsKeyEvent event(PR_TRUE, aEventType, this);
2543 nsPoint point;
2544
2545 point.x = 0;
2546 point.y = 0;
2547
2548 InitEvent(event, &point); // this add ref's event.widget
2549
2550 event.flags |= aFlags;
2551 event.charCode = aCharCode;
2552 event.keyCode = aKeyCode;
2553
2554 #ifdef KB_DEBUG
2555 static int cnt=0;
2556 printf("%d DispatchKE Type: %s charCode 0x%x keyCode 0x%x ", cnt++,
2557 (NS_KEY_PRESS == aEventType)?"PRESS":(aEventType == NS_KEY_UP?"Up":"Down"),
2558 event.charCode, event.keyCode);
2559 printf("Shift: %s Control %s Alt: %s Meta: %s\n",
2560 (mIsShiftDown?"D":"U"),
2561 (mIsControlDown?"D":"U"),
2562 (mIsAltDown?"D":"U"),
2563 (mIsMetaDown?"D":"U"));
2564 #endif
2565
2566 event.isShift = mIsShiftDown;
2567 event.isControl = mIsControlDown;
2568 event.isMeta = mIsMetaDown;
2569 event.isAlt = mIsAltDown;
2570
2571 PRBool result = DispatchWindowEvent(&event);
2572 NS_RELEASE(event.widget);
2573
2574 return result;
2575 }
2576
2577 //-------------------------------------------------------------------------
2578 //
2579 // WM_DESTROY has been called
2580 //
2581 //-------------------------------------------------------------------------
2582 void nsWindow::OnDestroy()
2583 {
2584 mOnDestroyCalled = PR_TRUE;
2585
2586 // release references to children, device context, toolkit, and app shell
2587 nsBaseWidget::OnDestroy();
2588
2589 // dispatch the event
2590 if (!mIsDestroying)
2591 {
2592 // dispatching of the event may cause the reference count to drop to 0
2593 // and result in this object being destroyed. To avoid that, add a reference
2594 // and then release it after dispatching the event
2595 AddRef();
2596 DispatchStandardEvent(NS_DESTROY);
2597 Release();
2598 }
2599 }
2600
2601 //-------------------------------------------------------------------------
2602 //
2603 // Move
2604 //
2605 //-------------------------------------------------------------------------
2606 PRBool nsWindow::OnMove(PRInt32 aX, PRInt32 aY)
2607 {
2608 nsGUIEvent event(PR_TRUE, NS_MOVE, this);
2609 InitEvent(event);
2610 event.point.x = aX;
2611 event.point.y = aY;
2612
2613 PRBool result = DispatchWindowEvent(&event);
2614 NS_RELEASE(event.widget);
2615 return result;
2616 }
2617
2618 void nsWindow::OnWheel(PRInt32 aDirection, uint32 aButtons, BPoint aPoint, nscoord aDelta)
2619 {
2620 // we don't use the mIsXDown bools because
2621 // they get reset on Gecko reload (makes it harder
2622 // to use stuff like Alt+Wheel)
2623
2624 nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
2625 uint32 mod (modifiers());
2626 scrollEvent.isControl = mod & B_CONTROL_KEY;
2627 scrollEvent.isShift = mod & B_SHIFT_KEY;
2628 scrollEvent.isAlt = mod & B_COMMAND_KEY;
2629 scrollEvent.isMeta = mod & B_OPTION_KEY;
2630
2631 scrollEvent.scrollFlags = aDirection;
2632 scrollEvent.delta = aDelta;
2633 scrollEvent.time = PR_IntervalNow();
2634 scrollEvent.point.x = nscoord(aPoint.x);
2635 scrollEvent.point.y = nscoord(aPoint.y);
2636
2637 nsEventStatus rv;
2638 DispatchEvent (&scrollEvent, rv);
2639 }
2640
2641 //-------------------------------------------------------------------------
2642 //
2643 // Paint
2644 //
2645 //-------------------------------------------------------------------------
2646 nsresult nsWindow::OnPaint(BRegion *breg)
2647 {
2648 nsresult rv = NS_ERROR_FAILURE;
2649 if (mView && mView->LockLooper())
2650 {
2651 // Substracting area from paintregion
2652 mView->Validate(breg);
2653 // looks like it should be done by Mozilla via nsRenderingContext methods,
2654 // but we saw in some cases how it follows Win32 ideas and don't care about clipping there
2655 mView->ConstrainClippingRegion(breg);
2656 mView->UnlockLooper();
2657 }
2658 else
2659 return rv;
2660 BRect br = breg->Frame();
2661 if (!br.IsValid() || !mEventCallback || !mView || (eWindowType_child != mWindowType && eWindowType_popup != mWindowType))
2662 return rv;
2663 nsRect nsr(nscoord(br.left), nscoord(br.top),
2664 nscoord(br.IntegerWidth() + 1), nscoord(br.IntegerHeight() + 1));
2665 mUpdateArea->SetTo(0,0,0,0);
2666 int numrects = breg->CountRects();
2667 for (int i = 0; i< numrects; i++)
2668 {
2669 BRect br = breg->RectAt(i);
2670 mUpdateArea->Union(int(br.left), int(br.top),
2671 br.IntegerWidth() + 1, br.IntegerHeight() + 1);
2672 }
2673
2674
2675 nsPaintEvent event(PR_TRUE, NS_PAINT, this);
2676
2677 InitEvent(event);
2678 event.region = mUpdateArea;
2679 event.rect = &nsr;
2680 event.renderingContext = GetRenderingContext();
2681 if (event.renderingContext != nsnull)
2682 {
2683 // TODO: supply nsRenderingContextBeOS with font, colors and other state variables here.
2684 // It will help toget rid of some hacks in LockAndUpdateView and
2685 // allow non-permanent nsDrawingSurface for BeOS - currently it fails for non-bitmapped BViews/widgets.
2686 // Something like this:
2687 //if (mFontMetrics)
2688 // event.renderingContext->SetFont(mFontMetrics);
2689 rv = DispatchWindowEvent(&event) ? NS_OK : NS_ERROR_FAILURE;
2690 NS_RELEASE(event.renderingContext);
2691 }
2692
2693 NS_RELEASE(event.widget);
2694 return rv;
2695 }
2696
2697
2698 //-------------------------------------------------------------------------
2699 //
2700 // Send a resize message to the listener
2701 //
2702 //-------------------------------------------------------------------------
2703 PRBool nsWindow::OnResize(nsRect &aWindowRect)
2704 {
2705 // call the event callback
2706 if (mEventCallback)
2707 {
2708 nsSizeEvent event(PR_TRUE, NS_SIZE, this);
2709 InitEvent(event);
2710 event.windowSize = &aWindowRect;
2711 // We have same size for windows rect and "client area" rect
2712 event.mWinWidth = aWindowRect.width;
2713 event.mWinHeight = aWindowRect.height;
2714 PRBool result = DispatchWindowEvent(&event);
2715 NS_RELEASE(event.widget);
2716 return result;
2717 }
2718 return PR_FALSE;
2719 }
2720
2721
2722
2723 //-------------------------------------------------------------------------
2724 //
2725 // Deal with all sort of mouse event
2726 //
2727 //-------------------------------------------------------------------------
2728 PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, nsPoint aPoint, PRUint32 clicks, PRUint32 mod)
2729 {
2730 PRBool result = PR_FALSE;
2731 if (nsnull != mEventCallback || nsnull != mMouseListener)
2732 {
2733 nsMouseEvent event(PR_TRUE, aEventType, this, nsMouseEvent::eReal);
2734 InitEvent (event, &aPoint);
2735 event.isShift = mod & B_SHIFT_KEY;
2736 event.isControl = mod & B_CONTROL_KEY;
2737 event.isAlt = mod & B_COMMAND_KEY;
2738 event.isMeta = mod & B_OPTION_KEY;
2739 event.clickCount = clicks;
2740
2741 // call the event callback
2742 if (nsnull != mEventCallback)
2743 {
2744 result = DispatchWindowEvent(&event);
2745 NS_RELEASE(event.widget);
2746 return result;
2747 }
2748 else
2749 {
2750 switch(aEventType)
2751 {
2752 case NS_MOUSE_MOVE :
2753 result = ConvertStatus(mMouseListener->MouseMoved(event));
2754 break;
2755
2756 case NS_MOUSE_LEFT_BUTTON_DOWN :
2757 case NS_MOUSE_MIDDLE_BUTTON_DOWN :
2758 case NS_MOUSE_RIGHT_BUTTON_DOWN :
2759 result = ConvertStatus(mMouseListener->MousePressed(event));
2760 break;
2761
2762 case NS_MOUSE_LEFT_BUTTON_UP :
2763 case NS_MOUSE_MIDDLE_BUTTON_UP :
2764 case NS_MOUSE_RIGHT_BUTTON_UP :
2765 result = ConvertStatus(mMouseListener->MouseReleased(event)) && ConvertStatus(mMouseListener->MouseClicked(event));
2766 break;
2767 }
2768 NS_RELEASE(event.widget);
2769 return result;
2770 }
2771 }
2772
2773 return PR_FALSE;
2774 }
2775
2776 //-------------------------------------------------------------------------
2777 //
2778 // Deal with focus messages
2779 //
2780 //-------------------------------------------------------------------------
2781 PRBool nsWindow::DispatchFocus(PRUint32 aEventType)
2782 {
2783 // call the event callback
2784 if (mEventCallback) {
2785 return(DispatchStandardEvent(aEventType));
2786 }
2787
2788 return PR_FALSE;
2789 }
2790
2791 NS_METHOD nsWindow::SetTitle(const nsAString& aTitle)
2792 {
2793 if (mView && mView->LockLooper())
2794 {
2795 mView->Window()->SetTitle(NS_ConvertUTF16toUTF8(aTitle).get());
2796 mView->UnlockLooper();
2797 }
2798 return NS_OK;
2799 }
2800
2801 //----------------------------------------------------
2802 //
2803 // Get/Set the preferred size
2804 //
2805 //----------------------------------------------------
2806 NS_METHOD nsWindow::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight)
2807 {
2808 // TODO: Check to see how often this is called. If too much, leave as is,
2809 // otherwise, call mView->GetPreferredSize
2810 aWidth = mPreferredWidth;
2811 aHeight = mPreferredHeight;
2812 return NS_ERROR_FAILURE;
2813 }
2814
2815 NS_METHOD nsWindow::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
2816 {
2817 mPreferredWidth = aWidth;
2818 mPreferredHeight = aHeight;
2819 return NS_OK;
2820 }
2821
2822 //----------------------------------------------------
2823 // Special Sub-Class
2824 //----------------------------------------------------
2825 nsIWidgetStore::nsIWidgetStore( nsIWidget *aWidget )
2826 : mWidget( aWidget )
2827 {
2828 // NS_ADDREF/NS_RELEASE is not needed here.
2829 // This class is used as internal (BeOS native) object of nsWindow,
2830 // so it must not addref/release nsWindow here.
2831 // Otherwise, nsWindow object will leak. (Makoto Hamanaka)
2832 }
2833
2834 nsIWidgetStore::~nsIWidgetStore()
2835 {
2836 }
2837
2838 nsIWidget *nsIWidgetStore::GetMozillaWidget(void)
2839 {
2840 return mWidget;
2841 }
2842
2843 //----------------------------------------------------
2844 // BeOS Sub-Class Window
2845 //----------------------------------------------------
2846
2847 nsWindowBeOS::nsWindowBeOS( nsIWidget *aWidgetWindow, BRect aFrame, const char *aName, window_look aLook,
2848 window_feel aFeel, int32 aFlags, int32 aWorkspace )
2849 : BWindow( aFrame, aName, aLook, aFeel, aFlags, aWorkspace ),
2850 nsIWidgetStore( aWidgetWindow )
2851 {
2852 fJustGotBounds = true;
2853 }
2854
2855 nsWindowBeOS::~nsWindowBeOS()
2856 {
2857 //placeholder for clean up
2858 }
2859
2860 bool nsWindowBeOS::QuitRequested( void )
2861 {
2862 if (CountChildren() != 0)
2863 {
2864 nsWindow *w = (nsWindow *)GetMozillaWidget();
2865 nsToolkit *t;
2866 if (w && (t = w->GetToolkit()) != 0)
2867 {
2868 MethodInfo *info = nsnull;
2869 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::CLOSEWINDOW)))
2870 t->CallMethodAsync(info);
2871 NS_RELEASE(t);
2872 }
2873 }
2874 return true;
2875 }
2876
2877 void nsWindowBeOS::MessageReceived(BMessage *msg)
2878 {
2879 // Temp replacement for real DnD. Supports file drop onto window.
2880 if (msg->what == B_SIMPLE_DATA)
2881 {
2882 be_app_messenger.SendMessage(msg);
2883 }
2884 BWindow::MessageReceived(msg);
2885 }
2886
2887 // This function calls KeyDown() for Alt+whatever instead of app_server
2888 void nsWindowBeOS::DispatchMessage(BMessage *msg, BHandler *handler)
2889 {
2890 if (msg->what == B_KEY_DOWN && modifiers() & B_COMMAND_KEY) {
2891 BString bytes;
2892 if (B_OK == msg->FindString("bytes", &bytes)) {
2893 BView *view = this->CurrentFocus();
2894 if (view)
2895 view->KeyDown(bytes.String(), bytes.Length());
2896 }
2897 if (strcmp(bytes.String(),"w") && strcmp(bytes.String(),"W"))
2898 BWindow::DispatchMessage(msg, handler);
2899 }
2900 // In some cases the message don't reach QuitRequested() hook,
2901 // so do it here
2902 else if(msg->what == B_QUIT_REQUESTED)
2903 {
2904 // tells nsWindow to kill me
2905 nsWindow *w = (nsWindow *)GetMozillaWidget();
2906 nsToolkit *t;
2907 if (w && (t = w->GetToolkit()) != 0)
2908 {
2909 MethodInfo *info = nsnull;
2910 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::CLOSEWINDOW)))
2911 t->CallMethodAsync(info);
2912 NS_RELEASE(t);
2913 }
2914 }
2915 else
2916 BWindow::DispatchMessage(msg, handler);
2917 }
2918
2919 //This method serves single purpose here - allows Mozilla to save current window position,
2920 //and restore position on new start.
2921 void nsWindowBeOS::FrameMoved(BPoint origin)
2922 {
2923
2924 //determine if the window position actually changed
2925 if (origin.x == lastWindowPoint.x && origin.x == lastWindowPoint.x)
2926 {
2927 //it didn't - don't bother
2928 return;
2929 }
2930 lastWindowPoint = origin;
2931 nsWindow *w = (nsWindow *)GetMozillaWidget();
2932 nsToolkit *t;
2933 if (w && (t = w->GetToolkit()) != 0)
2934 {
2935 MethodInfo *info = nsnull;
2936 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONMOVE)))
2937 t->CallMethodAsync(info);
2938 NS_RELEASE(t);
2939 }
2940 }
2941
2942 void nsWindowBeOS::WindowActivated(bool active)
2943 {
2944 // Calls method ONACTIVATE to dispatch focus ACTIVATE messages
2945 nsWindow *w = (nsWindow *)GetMozillaWidget();
2946 nsToolkit *t;
2947 if (w && (t = w->GetToolkit()) != 0)
2948 {
2949 uint32 args[2];
2950 args[0] = (uint32)active;
2951 args[1] = (uint32)this;
2952 MethodInfo *info = nsnull;
2953 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONACTIVATE, 2, args)))
2954 t->CallMethodAsync(info);
2955 NS_RELEASE(t);
2956 }
2957 }
2958
2959 void nsWindowBeOS::WorkspacesChanged(uint32 oldworkspace, uint32 newworkspace)
2960 {
2961 if (oldworkspace == newworkspace)
2962 return;
2963 nsWindow *w = (nsWindow *)GetMozillaWidget();
2964 nsToolkit *t;
2965 if (w && (t = w->GetToolkit()) != 0)
2966 {
2967 uint32 args[2];
2968 args[0] = newworkspace;
2969 args[1] = oldworkspace;
2970 MethodInfo *info = nsnull;
2971 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONWORKSPACE, 2, args)))
2972 t->CallMethodAsync(info);
2973 NS_RELEASE(t);
2974 }
2975 }
2976
2977 void nsWindowBeOS::FrameResized(float width, float height)
2978 {
2979 // We have send message already, and Mozilla still didn't get it
2980 // so don't poke it endlessly with no reason
2981 if (!fJustGotBounds)
2982 return;
2983 nsWindow *w = (nsWindow *)GetMozillaWidget();
2984 nsToolkit *t;
2985 if (w && (t = w->GetToolkit()) != 0)
2986 {
2987 MethodInfo *info = nsnull;
2988 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONRESIZE)))
2989 {
2990 t->CallMethodAsync(info);
2991 //Memorize fact of sending message
2992 fJustGotBounds = false;
2993 }
2994 NS_RELEASE(t);
2995 }
2996 }
2997
2998 //----------------------------------------------------
2999 // BeOS Sub-Class View
3000 //----------------------------------------------------
3001
3002 nsViewBeOS::nsViewBeOS(nsIWidget *aWidgetWindow, BRect aFrame, const char *aName, uint32 aResizingMode, uint32 aFlags)
3003 : BView(aFrame, aName, aResizingMode, aFlags), nsIWidgetStore(aWidgetWindow), wheel(.0,.0)
3004 {
3005 SetViewColor(B_TRANSPARENT_COLOR);
3006 paintregion.MakeEmpty();
3007 buttons = 0;
3008 fRestoreMouseMask = false;
3009 fJustValidated = true;
3010 fWheelDispatched = true;
3011 fVisible = true;
3012 }
3013
3014 void nsViewBeOS::SetVisible(bool visible)
3015 {
3016 if (visible)
3017 SetFlags(Flags() | B_WILL_DRAW);
3018 else
3019 SetFlags(Flags() & ~B_WILL_DRAW);
3020 fVisible = visible;
3021 }
3022
3023 inline bool nsViewBeOS::Visible()
3024 {
3025 return fVisible;
3026 }
3027
3028 void nsViewBeOS::Draw(BRect updateRect)
3029 {
3030 // Ignore all, we are scrolling.
3031 if (!fVisible)
3032 return;
3033
3034 paintregion.Include(updateRect);
3035
3036 // We have send message already, and Mozilla still didn't get it
3037 // so don't poke it endlessly with no reason. Also don't send message
3038 // if update region is empty.
3039 if (paintregion.CountRects() == 0 || !paintregion.Frame().IsValid() || !fJustValidated)
3040 return;
3041 uint32 args[1];
3042 args[0] = (uint32)this;
3043 nsWindow *w = (nsWindow *)GetMozillaWidget();
3044 nsToolkit *t;
3045 if (w && (t = w->GetToolkit()) != 0)
3046 {
3047 MethodInfo *info = nsnull;
3048 info = new MethodInfo(w, w, nsSwitchToUIThread::ONPAINT, 1, args);
3049 if (info)
3050 {
3051 t->CallMethodAsync(info);
3052 //Memorize fact of sending message
3053 fJustValidated = false;
3054 }
3055 NS_RELEASE(t);
3056 }
3057 }
3058
3059 // Method to get update rects for asynchronous drawing.
3060 bool nsViewBeOS::GetPaintRegion(BRegion *r)
3061 {
3062
3063 // Mozilla got previous ONPAINT message,
3064 // ready for next event.
3065 fJustValidated = true;
3066 if (paintregion.CountRects() == 0)
3067 return false;
3068 r->Include(&paintregion);
3069 return true;
3070 }
3071
3072 // Method to remove painted rects from pending update region
3073 void nsViewBeOS::Validate(BRegion *reg)
3074 {
3075 paintregion.Exclude(reg);
3076 }
3077
3078 BPoint nsViewBeOS::GetWheel()
3079 {
3080 BPoint retvalue = wheel;
3081 // Mozilla got wheel event, so setting flag and cleaning delta storage
3082 fWheelDispatched = true;
3083 wheel.x = 0;
3084 wheel.y = 0;
3085 return retvalue;
3086 }
3087
3088 void nsViewBeOS::MouseDown(BPoint point)
3089 {
3090 if (!fRestoreMouseMask)
3091 mouseMask = SetMouseEventMask(B_POINTER_EVENTS);
3092 fRestoreMouseMask = true;
3093
3094 //To avoid generating extra mouseevents when there is no change in pos.
3095 mousePos = point;
3096
3097 uint32 clicks = 0;
3098 BMessage *msg = Window()->CurrentMessage();
3099 msg->FindInt32("buttons", (int32 *) &buttons);
3100 msg->FindInt32("clicks", (int32 *) &clicks);
3101
3102 if (0 == buttons)
3103 return;
3104
3105 nsWindow *w = (nsWindow *)GetMozillaWidget();
3106 if (w == NULL)
3107 return;
3108
3109 nsToolkit *t = w->GetToolkit();
3110 if (t == NULL)
3111 return;
3112
3113 int32 ev = (buttons & B_PRIMARY_MOUSE_BUTTON) ? NS_MOUSE_LEFT_BUTTON_DOWN :
3114 ((buttons & B_SECONDARY_MOUSE_BUTTON) ? NS_MOUSE_RIGHT_BUTTON_DOWN :
3115 NS_MOUSE_MIDDLE_BUTTON_DOWN);
3116 uint32 args[5];
3117 args[0] = ev;
3118 args[1] = (uint32) point.x;
3119 args[2] = (uint32) point.y;
3120 args[3] = clicks;
3121 args[4] = modifiers();
3122 MethodInfo *info = nsnull;
3123 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::BTNCLICK, 5, args)))
3124 t->CallMethodAsync(info);
3125 NS_RELEASE(t);
3126 }
3127
3128 void nsViewBeOS::MouseMoved(BPoint point, uint32 transit, const BMessage *msg)
3129 {
3130 //To avoid generating extra mouseevents when there is no change in pos.
3131 //and not entering exiting view.
3132 if (mousePos == point && (transit == B_INSIDE_VIEW || transit == B_OUTSIDE_VIEW))
3133 return;
3134
3135 mousePos = point;
3136
3137 //We didn't start the mouse down and there is no drag in progress, so ignore.
3138 if (NULL == msg && !fRestoreMouseMask && buttons)
3139 return;
3140
3141 nsWindow *w = (nsWindow *)GetMozillaWidget();
3142 if (w == NULL)
3143 return;
3144 nsToolkit *t = t = w->GetToolkit();
3145 if (t == NULL)
3146 return;
3147
3148 uint32 args[1];
3149 /* args[1] = (int32) point.x;
3150 args[2] = (int32) point.y;
3151 args[3] = modifiers();*/
3152
3153 switch (transit)
3154 {
3155 case B_ENTERED_VIEW:
3156 {
3157 args[0] = NULL != msg ? NS_DRAGDROP_ENTER : NS_MOUSE_ENTER;
3158 if (msg == NULL)
3159 break;
3160 nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
3161 dragService->StartDragSession();
3162 //As it may have come from the outside we need to update this.
3163 nsCOMPtr<nsIDragSessionBeOS> dragSessionBeOS = do_QueryInterface(dragService);
3164 dragSessionBeOS->UpdateDragMessageIfNeeded(new BMessage(*msg));
3165 }
3166 break;
3167 case B_EXITED_VIEW:
3168 {
3169 args[0] = NULL != msg ? NS_DRAGDROP_EXIT : NS_MOUSE_EXIT;
3170 if (msg == NULL)
3171 break;
3172 nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
3173 dragService->EndDragSession();
3174 }
3175 break;
3176 default:
3177 args[0]= msg == NULL ? NS_MOUSE_MOVE : NS_DRAGDROP_OVER;
3178 }
3179
3180 MethodInfo *moveInfo = nsnull;
3181 if (nsnull != (moveInfo = new MethodInfo(w, w, nsSwitchToUIThread::ONMOUSE, 1, args)))
3182 t->CallMethodAsync(moveInfo);
3183 NS_RELEASE(t);
3184 }
3185
3186 void nsViewBeOS::MouseUp(BPoint point)
3187 {
3188 if (fRestoreMouseMask)
3189 {
3190 SetMouseEventMask(mouseMask);
3191 fRestoreMouseMask = false;
3192 }
3193
3194 //To avoid generating extra mouseevents when there is no change in pos.
3195 mousePos = point;
3196
3197 int32 ev = (buttons & B_PRIMARY_MOUSE_BUTTON) ? NS_MOUSE_LEFT_BUTTON_UP :
3198 ((buttons & B_SECONDARY_MOUSE_BUTTON) ? NS_MOUSE_RIGHT_BUTTON_UP :
3199 NS_MOUSE_MIDDLE_BUTTON_UP);
3200
3201 buttons = 0;
3202
3203 nsWindow *w = (nsWindow *)GetMozillaWidget();
3204 if (w == NULL)
3205 return;
3206 nsToolkit *t = t = w->GetToolkit();
3207 if (t == NULL)
3208 return;
3209
3210 uint32 args[5];
3211 args[0] = ev;
3212 args[1] = (uint32) point.x;
3213 args[2] = (int32) point.y;
3214 args[3] = 0;
3215 args[4] = modifiers();
3216 MethodInfo *info = nsnull;
3217 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::BTNCLICK, 5, args)))
3218 t->CallMethodAsync(info);
3219 NS_RELEASE(t);
3220 }
3221
3222 void nsViewBeOS::MessageReceived(BMessage *msg)
3223 {
3224 if(msg->WasDropped())
3225 {
3226 nsWindow *w = (nsWindow *)GetMozillaWidget();
3227 if (w == NULL)
3228 return;
3229 nsToolkit *t = t = w->GetToolkit();
3230 if (t == NULL)
3231 return;
3232
3233 uint32 args[4];
3234 args[0] = NS_DRAGDROP_DROP;
3235
3236 //Drop point is in screen-cordinates
3237 BPoint aPoint = ConvertFromScreen(msg->DropPoint());
3238
3239 args[1] = (uint32) aPoint.x;
3240 args[2] = (uint32) aPoint.y;
3241 args[3] = modifiers();
3242
3243 MethodInfo *info = new MethodInfo(w, w, nsSwitchToUIThread::ONDROP, 4, args);
3244 t->CallMethodAsync(info);
3245 BView::MessageReceived(msg);
3246 return;
3247 }
3248
3249 switch(msg->what)
3250 {
3251 //Native drag'n'drop negotiation
3252 case B_COPY_TARGET:
3253 case B_MOVE_TARGET:
3254 case B_LINK_TARGET:
3255 case B_TRASH_TARGET:
3256 {
3257 nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
3258 nsCOMPtr<nsIDragSessionBeOS> dragSessionBeOS = do_QueryInterface(dragService);
3259 dragSessionBeOS->TransmitData(new BMessage(*msg));
3260 }
3261 break;
3262 case B_UNMAPPED_KEY_DOWN:
3263 //printf("unmapped_key_down\n");
3264 KeyDown(NULL, 0);
3265 break;
3266
3267 case B_UNMAPPED_KEY_UP:
3268 //printf("unmapped_key_up\n");
3269 KeyUp(NULL, 0);
3270 break;
3271
3272 case B_MOUSE_WHEEL_CHANGED:
3273 {
3274 float wheel_y;
3275 float wheel_x;
3276
3277 msg->FindFloat ("be:wheel_delta_y", &wheel_y);
3278 msg->FindFloat ("be:wheel_delta_x", &wheel_x);
3279 wheel.x += wheel_x;
3280 wheel.y += wheel_y;
3281
3282 if(!fWheelDispatched || (nscoord(wheel_x) == 0 && nscoord(wheel_y) == 0))
3283 return;
3284 uint32 args[1];
3285 args[0] = (uint32)this;
3286 nsWindow *w = (nsWindow *)GetMozillaWidget();
3287 nsToolkit *t;
3288
3289 if (w && (t = w->GetToolkit()) != 0)
3290 {
3291
3292 MethodInfo *info = nsnull;
3293 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONWHEEL, 1, args)))
3294 {
3295 t->CallMethodAsync(info);
3296 fWheelDispatched = false;
3297
3298 }
3299 NS_RELEASE(t);
3300 }
3301 }
3302 break;
3303
3304 #if defined(BeIME)
3305 case B_INPUT_METHOD_EVENT:
3306 DoIME(msg);
3307 break;
3308 #endif
3309 default :
3310 BView::MessageReceived(msg);
3311 break;
3312 }
3313 }
3314
3315 void nsViewBeOS::KeyDown(const char *bytes, int32 numBytes)
3316 {
3317 nsWindow *w = (nsWindow *)GetMozillaWidget();
3318 nsToolkit *t;
3319 int32 keycode = 0;
3320 int32 rawcode = 0;
3321
3322 BMessage *msg = this->Window()->CurrentMessage();
3323 if (msg) {
3324 msg->FindInt32("key", &keycode);
3325 msg->FindInt32("raw_char", &rawcode);
3326 }
3327
3328 if (w && (t = w->GetToolkit()) != 0) {
3329 uint32 bytebuf = 0;
3330 uint8 *byteptr = (uint8 *)&bytebuf;
3331 for(int32 i = 0; i < numBytes; i++)
3332 byteptr[i] = bytes[i];
3333
3334 uint32 args[6];
3335 args[0] = NS_KEY_DOWN;
3336 args[1] = bytebuf;
3337 args[2] = numBytes;
3338 args[3] = modifiers();
3339 args[4] = keycode;
3340 args[5] = rawcode;
3341 MethodInfo *info = nsnull;
3342 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONKEY, 6, args)))
3343 t->CallMethodAsync(info);
3344 NS_RELEASE(t);
3345 }
3346 }
3347
3348 void nsViewBeOS::KeyUp(const char *bytes, int32 numBytes)
3349 {
3350 nsWindow *w = (nsWindow *)GetMozillaWidget();
3351 nsToolkit *t;
3352 int32 keycode = 0;
3353 int32 rawcode = 0;
3354 BMessage *msg = this->Window()->CurrentMessage();
3355 if (msg) {
3356 msg->FindInt32("key", &keycode);
3357 msg->FindInt32("raw_char", &rawcode);
3358 }
3359
3360 if (w && (t = w->GetToolkit()) != 0) {
3361 uint32 bytebuf = 0;
3362 uint8 *byteptr = (uint8 *)&bytebuf;
3363 for(int32 i = 0; i < numBytes; i++)
3364 byteptr[i] = bytes[i];
3365
3366 uint32 args[6];
3367 args[0] = NS_KEY_UP;
3368 args[1] = (int32)bytebuf;
3369 args[2] = numBytes;
3370 args[3] = modifiers();
3371 args[4] = keycode;
3372 args[5] = rawcode;
3373 MethodInfo *info = nsnull;
3374 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::ONKEY, 6, args)))
3375 t->CallMethodAsync(info);
3376 NS_RELEASE(t);
3377 }
3378 }
3379
3380 void nsViewBeOS::MakeFocus(bool focused)
3381 {
3382 if (!IsFocus() && focused)
3383 BView::MakeFocus(focused);
3384 uint32 args[1];
3385 args[0] = (uint32)this;
3386 nsWindow *w = (nsWindow *)GetMozillaWidget();
3387 nsToolkit *t;
3388 if (w && (t = w->GetToolkit()) != 0)
3389 {
3390 MethodInfo *info = nsnull;
3391 if (!focused)
3392 {
3393 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::KILL_FOCUS,1,args)))
3394 t->CallMethodAsync(info);
3395 }
3396 #ifdef DEBUG_FOCUS
3397 else
3398 {
3399 if (nsnull != (info = new MethodInfo(w, w, nsSwitchToUIThread::GOT_FOCUS,1,args)))
3400 t->CallMethodAsync(info);
3401 }
3402 #endif
3403 NS_RELEASE(t);
3404 }
3405 }
3406
3407 #if defined(BeIME)
3408 // Inline Input Method implementation
3409 void nsViewBeOS::DoIME(BMessage *msg)
3410 {
3411 nsWindow *w = (nsWindow *)GetMozillaWidget();
3412 nsToolkit *t;
3413
3414 if(w && (t = w->GetToolkit()) != 0)
3415 {
3416 ssize_t size = msg->FlattenedSize();
3417 int32 argc = (size+3)/4;
3418 uint32 *args = new uint32[argc];
3419 if (args)
3420 {
3421 msg->Flatten((char*)args, size);
3422 MethodInfo *info = new MethodInfo(w, w, nsSwitchToUIThread::ONIME, argc, args);
3423 if (info)
3424 {
3425 t->CallMethodAsync(info);
3426 NS_RELEASE(t);
3427 }
3428 delete[] args;
3429 }
3430 }
3431 }
3432 #endif
3433