|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim:expandtab:shiftwidth=4:tabstop=4: |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include "mozilla/ArrayUtils.h" |
|
9 #include "mozilla/MiscEvents.h" |
|
10 #include "mozilla/MouseEvents.h" |
|
11 #include "mozilla/TextEvents.h" |
|
12 #include "mozilla/TouchEvents.h" |
|
13 |
|
14 #include <QGuiApplication> |
|
15 #include <QtGui/QCursor> |
|
16 #include <QIcon> |
|
17 #include <QMouseEvent> |
|
18 #include <QWheelEvent> |
|
19 #include <QResizeEvent> |
|
20 #include <QPaintEngine> |
|
21 #include <QMimeData> |
|
22 #include <QScreen> |
|
23 |
|
24 #include <QtCore/QDebug> |
|
25 #include <QtCore/QEvent> |
|
26 #include <QtCore/QVariant> |
|
27 #include <algorithm> |
|
28 |
|
29 #ifdef MOZ_X11 |
|
30 #include <X11/Xlib.h> |
|
31 #include <X11/Xutil.h> |
|
32 #endif //MOZ_X11 |
|
33 |
|
34 #include "nsXULAppAPI.h" |
|
35 |
|
36 #include "prlink.h" |
|
37 |
|
38 #include "nsWindow.h" |
|
39 #include "mozqwidget.h" |
|
40 |
|
41 #include "nsIdleService.h" |
|
42 #include "nsRenderingContext.h" |
|
43 #include "nsIRollupListener.h" |
|
44 #include "nsWidgetsCID.h" |
|
45 #include "nsQtKeyUtils.h" |
|
46 #include "mozilla/Services.h" |
|
47 #include "mozilla/Preferences.h" |
|
48 #include "mozilla/Likely.h" |
|
49 #include "mozilla/layers/LayersTypes.h" |
|
50 #include "nsIWidgetListener.h" |
|
51 #include "ClientLayerManager.h" |
|
52 #include "BasicLayers.h" |
|
53 |
|
54 #include "nsIStringBundle.h" |
|
55 #include "nsGfxCIID.h" |
|
56 |
|
57 #include "imgIContainer.h" |
|
58 #include "nsGfxCIID.h" |
|
59 #include "nsIInterfaceRequestorUtils.h" |
|
60 #include "nsAutoPtr.h" |
|
61 |
|
62 #include "gfxQtPlatform.h" |
|
63 |
|
64 #include "nsIDOMWheelEvent.h" |
|
65 |
|
66 #include "GLContext.h" |
|
67 |
|
68 #ifdef MOZ_X11 |
|
69 #include "keysym2ucs.h" |
|
70 #endif |
|
71 |
|
72 #include "Layers.h" |
|
73 #include "GLContextProvider.h" |
|
74 |
|
75 using namespace mozilla; |
|
76 using namespace mozilla::gl; |
|
77 using namespace mozilla::widget; |
|
78 using namespace mozilla::gfx; |
|
79 using namespace mozilla::layers; |
|
80 using mozilla::gl::GLContext; |
|
81 |
|
82 #define kWindowPositionSlop 20 |
|
83 |
|
84 // Qt |
|
85 static const int WHEEL_DELTA = 120; |
|
86 static bool gGlobalsInitialized = false; |
|
87 static bool sAltGrModifier = false; |
|
88 |
|
89 static void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem); |
|
90 static bool is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY); |
|
91 static bool isContextMenuKeyEvent(const QKeyEvent *qe); |
|
92 static void InitKeyEvent(WidgetKeyboardEvent &aEvent, QKeyEvent *aQEvent); |
|
93 |
|
94 nsWindow::nsWindow() |
|
95 { |
|
96 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this)); |
|
97 |
|
98 mIsTopLevel = false; |
|
99 mIsDestroyed = false; |
|
100 mIsShown = false; |
|
101 mEnabled = true; |
|
102 mWidget = nullptr; |
|
103 mVisible = false; |
|
104 mActivatePending = false; |
|
105 mWindowType = eWindowType_child; |
|
106 mSizeState = nsSizeMode_Normal; |
|
107 mLastSizeMode = nsSizeMode_Normal; |
|
108 mQCursor = Qt::ArrowCursor; |
|
109 mNeedsResize = false; |
|
110 mNeedsMove = false; |
|
111 mListenForResizes = false; |
|
112 mNeedsShow = false; |
|
113 mTimerStarted = false; |
|
114 mMoveEvent.needDispatch = false; |
|
115 |
|
116 if (!gGlobalsInitialized) { |
|
117 gfxPlatform::GetPlatform(); |
|
118 gGlobalsInitialized = true; |
|
119 } |
|
120 |
|
121 memset(mKeyDownFlags, 0, sizeof(mKeyDownFlags)); |
|
122 |
|
123 mIsTransparent = false; |
|
124 |
|
125 mCursor = eCursor_standard; |
|
126 } |
|
127 |
|
128 nsWindow::~nsWindow() |
|
129 { |
|
130 LOG(("%s [%p]\n", __PRETTY_FUNCTION__, (void *)this)); |
|
131 |
|
132 Destroy(); |
|
133 } |
|
134 |
|
135 nsresult |
|
136 nsWindow::Create(nsIWidget *aParent, |
|
137 nsNativeWidget aNativeParent, |
|
138 const nsIntRect &aRect, |
|
139 nsDeviceContext *aContext, |
|
140 nsWidgetInitData *aInitData) |
|
141 { |
|
142 // only set the base parent if we're not going to be a dialog or a |
|
143 // toplevel |
|
144 nsIWidget *baseParent = aParent; |
|
145 |
|
146 // initialize all the common bits of this class |
|
147 BaseCreate(baseParent, aRect, aContext, aInitData); |
|
148 |
|
149 mVisible = true; |
|
150 |
|
151 // and do our common creation |
|
152 mParent = (nsWindow *)aParent; |
|
153 |
|
154 // save our bounds |
|
155 mBounds = aRect; |
|
156 |
|
157 // find native parent |
|
158 MozQWidget *parent = nullptr; |
|
159 |
|
160 if (aParent != nullptr) { |
|
161 parent = static_cast<MozQWidget*>(aParent->GetNativeData(NS_NATIVE_WIDGET)); |
|
162 } else if (aNativeParent != nullptr) { |
|
163 parent = static_cast<MozQWidget*>(aNativeParent); |
|
164 if (parent && mParent == nullptr) { |
|
165 mParent = parent->getReceiver(); |
|
166 } |
|
167 } |
|
168 |
|
169 LOG(("Create: nsWindow [%p] mWidget:[%p] parent:[%p], natPar:[%p] mParent:%p\n", (void *)this, (void*)mWidget, parent, aNativeParent, mParent)); |
|
170 |
|
171 // ok, create our QGraphicsWidget |
|
172 mWidget = createQWidget(parent, aInitData); |
|
173 |
|
174 if (!mWidget) { |
|
175 return NS_ERROR_OUT_OF_MEMORY; |
|
176 } |
|
177 |
|
178 |
|
179 // resize so that everything is set to the right dimensions |
|
180 Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false); |
|
181 |
|
182 // check if we should listen for resizes |
|
183 mListenForResizes = (aNativeParent || |
|
184 (aInitData && aInitData->mListenForResizes)); |
|
185 |
|
186 return NS_OK; |
|
187 } |
|
188 |
|
189 MozQWidget* |
|
190 nsWindow::createQWidget(MozQWidget* parent, |
|
191 nsWidgetInitData* aInitData) |
|
192 { |
|
193 const char *windowName = nullptr; |
|
194 Qt::WindowFlags flags = Qt::Widget; |
|
195 |
|
196 // ok, create our windows |
|
197 switch (mWindowType) { |
|
198 case eWindowType_dialog: |
|
199 windowName = "topLevelDialog"; |
|
200 flags = Qt::Dialog; |
|
201 break; |
|
202 case eWindowType_popup: |
|
203 windowName = "topLevelPopup"; |
|
204 flags = Qt::Popup; |
|
205 break; |
|
206 case eWindowType_toplevel: |
|
207 windowName = "topLevelWindow"; |
|
208 flags = Qt::Window; |
|
209 break; |
|
210 case eWindowType_invisible: |
|
211 windowName = "topLevelInvisible"; |
|
212 break; |
|
213 case eWindowType_child: |
|
214 case eWindowType_plugin: |
|
215 default: // sheet |
|
216 windowName = "paintArea"; |
|
217 break; |
|
218 } |
|
219 |
|
220 MozQWidget* widget = new MozQWidget(this, parent); |
|
221 if (!widget) { |
|
222 return nullptr; |
|
223 } |
|
224 |
|
225 widget->setObjectName(QString(windowName)); |
|
226 if (mWindowType == eWindowType_invisible) { |
|
227 widget->setVisibility(QWindow::Hidden); |
|
228 } |
|
229 if (mWindowType == eWindowType_dialog) { |
|
230 widget->setModality(Qt::WindowModal); |
|
231 } |
|
232 |
|
233 widget->create(); |
|
234 |
|
235 // create a QGraphicsView if this is a new toplevel window |
|
236 LOG(("nsWindow::%s [%p] Created Window: %s, widget:%p, par:%p\n", __FUNCTION__, (void *)this, windowName, widget, parent)); |
|
237 |
|
238 return widget; |
|
239 } |
|
240 |
|
241 NS_IMETHODIMP |
|
242 nsWindow::Destroy(void) |
|
243 { |
|
244 if (mIsDestroyed || !mWidget) { |
|
245 return NS_OK; |
|
246 } |
|
247 |
|
248 LOG(("nsWindow::Destroy [%p]\n", (void *)this)); |
|
249 mIsDestroyed = true; |
|
250 |
|
251 /** Need to clean our LayerManager up while still alive */ |
|
252 if (mLayerManager) { |
|
253 mLayerManager->Destroy(); |
|
254 } |
|
255 mLayerManager = nullptr; |
|
256 |
|
257 // It is safe to call DestroyeCompositor several times (here and |
|
258 // in the parent class) since it will take effect only once. |
|
259 // The reason we call it here is because on gtk platforms we need |
|
260 // to destroy the compositor before we destroy the gdk window (which |
|
261 // destroys the the gl context attached to it). |
|
262 DestroyCompositor(); |
|
263 |
|
264 ClearCachedResources(); |
|
265 |
|
266 nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); |
|
267 if (rollupListener) { |
|
268 nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget(); |
|
269 if (static_cast<nsIWidget *>(this) == rollupWidget) { |
|
270 rollupListener->Rollup(0, nullptr, nullptr); |
|
271 } |
|
272 } |
|
273 |
|
274 Show(false); |
|
275 |
|
276 // walk the list of children and call destroy on them. Have to be |
|
277 // careful, though -- calling destroy on a kid may actually remove |
|
278 // it from our child list, losing its sibling links. |
|
279 for (nsIWidget* kid = mFirstChild; kid; ) { |
|
280 nsIWidget* next = kid->GetNextSibling(); |
|
281 kid->Destroy(); |
|
282 kid = next; |
|
283 } |
|
284 |
|
285 // Destroy thebes surface now. Badness can happen if we destroy |
|
286 // the surface after its X Window. |
|
287 if (mWidget) { |
|
288 mWidget->dropReceiver(); |
|
289 |
|
290 // Call deleteLater instead of delete; Qt still needs the object |
|
291 // to be valid even after sending it a Close event. We could |
|
292 // also set WA_DeleteOnClose, but this gives us more control. |
|
293 mWidget->deleteLater(); |
|
294 } |
|
295 mWidget = nullptr; |
|
296 |
|
297 OnDestroy(); |
|
298 |
|
299 return NS_OK; |
|
300 } |
|
301 |
|
302 NS_IMETHODIMP |
|
303 nsWindow::Show(bool aState) |
|
304 { |
|
305 LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState)); |
|
306 if (aState == mIsShown) { |
|
307 return NS_OK; |
|
308 } |
|
309 |
|
310 // Clear our cached resources when the window is hidden. |
|
311 if (mIsShown && !aState) { |
|
312 ClearCachedResources(); |
|
313 } |
|
314 |
|
315 mIsShown = aState; |
|
316 |
|
317 if ((aState && !AreBoundsSane()) || !mWidget) { |
|
318 LOG(("\tbounds are insane or window hasn't been created yet\n")); |
|
319 mNeedsShow = true; |
|
320 return NS_OK; |
|
321 } |
|
322 |
|
323 if (aState) { |
|
324 if (mNeedsMove) { |
|
325 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, |
|
326 false); |
|
327 } else if (mNeedsResize) { |
|
328 NativeResize(mBounds.width, mBounds.height, false); |
|
329 } |
|
330 } |
|
331 else { |
|
332 // If someone is hiding this widget, clear any needing show flag. |
|
333 mNeedsShow = false; |
|
334 } |
|
335 |
|
336 NativeShow(aState); |
|
337 |
|
338 return NS_OK; |
|
339 } |
|
340 |
|
341 bool |
|
342 nsWindow::IsVisible() const |
|
343 { |
|
344 return mIsShown; |
|
345 } |
|
346 |
|
347 NS_IMETHODIMP |
|
348 nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) |
|
349 { |
|
350 if (!mWidget) { |
|
351 return NS_ERROR_FAILURE; |
|
352 } |
|
353 |
|
354 int32_t screenWidth = qApp->primaryScreen()->size().width(); |
|
355 int32_t screenHeight = qApp->primaryScreen()->size().height(); |
|
356 |
|
357 if (aAllowSlop) { |
|
358 if (*aX < (kWindowPositionSlop - mBounds.width)) |
|
359 *aX = kWindowPositionSlop - mBounds.width; |
|
360 if (*aX > (screenWidth - kWindowPositionSlop)) |
|
361 *aX = screenWidth - kWindowPositionSlop; |
|
362 if (*aY < (kWindowPositionSlop - mBounds.height)) |
|
363 *aY = kWindowPositionSlop - mBounds.height; |
|
364 if (*aY > (screenHeight - kWindowPositionSlop)) |
|
365 *aY = screenHeight - kWindowPositionSlop; |
|
366 } else { |
|
367 if (*aX < 0) |
|
368 *aX = 0; |
|
369 if (*aX > (screenWidth - mBounds.width)) |
|
370 *aX = screenWidth - mBounds.width; |
|
371 if (*aY < 0) |
|
372 *aY = 0; |
|
373 if (*aY > (screenHeight - mBounds.height)) |
|
374 *aY = screenHeight - mBounds.height; |
|
375 } |
|
376 |
|
377 return NS_OK; |
|
378 } |
|
379 |
|
380 NS_IMETHODIMP |
|
381 nsWindow::Move(double aX, double aY) |
|
382 { |
|
383 LOG(("nsWindow::Move [%p] %f %f\n", (void *)this, |
|
384 aX, aY)); |
|
385 |
|
386 int32_t x = NSToIntRound(aX); |
|
387 int32_t y = NSToIntRound(aY); |
|
388 |
|
389 if (mIsTopLevel) { |
|
390 SetSizeMode(nsSizeMode_Normal); |
|
391 } |
|
392 |
|
393 if (x == mBounds.x && y == mBounds.y) { |
|
394 return NS_OK; |
|
395 } |
|
396 |
|
397 mNeedsMove = false; |
|
398 |
|
399 // update the bounds |
|
400 QPoint pos(x, y); |
|
401 if (mIsTopLevel) { |
|
402 mWidget->setPosition(x, y); |
|
403 } |
|
404 else if (mWidget) { |
|
405 // the position of the widget is set relative to the parent |
|
406 // so we map the coordinates accordingly |
|
407 pos = mWidget->mapToGlobal(pos); |
|
408 mWidget->setPosition(pos); |
|
409 } |
|
410 |
|
411 mBounds.x = pos.x(); |
|
412 mBounds.y = pos.y(); |
|
413 |
|
414 NotifyRollupGeometryChange(); |
|
415 return NS_OK; |
|
416 } |
|
417 |
|
418 NS_IMETHODIMP |
|
419 nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) |
|
420 { |
|
421 mBounds.width = NSToIntRound(aWidth); |
|
422 mBounds.height = NSToIntRound(aHeight); |
|
423 |
|
424 if (!mWidget) |
|
425 return NS_OK; |
|
426 |
|
427 if (mIsShown) { |
|
428 if (AreBoundsSane()) { |
|
429 if (mIsTopLevel || mNeedsShow) |
|
430 NativeResize(mBounds.x, mBounds.y, |
|
431 mBounds.width, mBounds.height, aRepaint); |
|
432 else |
|
433 NativeResize(mBounds.width, mBounds.height, aRepaint); |
|
434 |
|
435 // Does it need to be shown because it was previously insane? |
|
436 if (mNeedsShow) { |
|
437 NativeShow(true); |
|
438 } |
|
439 } |
|
440 else { |
|
441 // If someone has set this so that the needs show flag is false |
|
442 // and it needs to be hidden, update the flag and hide the |
|
443 // window. This flag will be cleared the next time someone |
|
444 // hides the window or shows it. It also prevents us from |
|
445 // calling NativeShow(false) excessively on the window which |
|
446 // causes unneeded X traffic. |
|
447 if (!mNeedsShow) { |
|
448 mNeedsShow = true; |
|
449 NativeShow(false); |
|
450 } |
|
451 } |
|
452 } |
|
453 else if (AreBoundsSane() && mListenForResizes) { |
|
454 // For widgets that we listen for resizes for (widgets created |
|
455 // with native parents) we apparently _always_ have to resize. I |
|
456 // dunno why, but apparently we're lame like that. |
|
457 NativeResize(mBounds.width, mBounds.height, aRepaint); |
|
458 } |
|
459 else { |
|
460 mNeedsResize = true; |
|
461 } |
|
462 |
|
463 // synthesize a resize event if this isn't a toplevel |
|
464 if (mIsTopLevel || mListenForResizes) { |
|
465 nsEventStatus status; |
|
466 DispatchResizeEvent(mBounds, status); |
|
467 } |
|
468 |
|
469 NotifyRollupGeometryChange(); |
|
470 return NS_OK; |
|
471 } |
|
472 |
|
473 NS_IMETHODIMP |
|
474 nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, |
|
475 bool aRepaint) |
|
476 { |
|
477 mBounds.x = NSToIntRound(aX); |
|
478 mBounds.y = NSToIntRound(aY); |
|
479 mBounds.width = NSToIntRound(aWidth); |
|
480 mBounds.height = NSToIntRound(aHeight); |
|
481 |
|
482 mPlaced = true; |
|
483 |
|
484 if (!mWidget) { |
|
485 return NS_OK; |
|
486 } |
|
487 |
|
488 // Has this widget been set to visible? |
|
489 if (mIsShown) { |
|
490 // Are the bounds sane? |
|
491 if (AreBoundsSane()) { |
|
492 // Yep? Resize the window |
|
493 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, |
|
494 aRepaint); |
|
495 // Does it need to be shown because it was previously insane? |
|
496 if (mNeedsShow) |
|
497 NativeShow(true); |
|
498 } |
|
499 else { |
|
500 // If someone has set this so that the needs show flag is false |
|
501 // and it needs to be hidden, update the flag and hide the |
|
502 // window. This flag will be cleared the next time someone |
|
503 // hides the window or shows it. It also prevents us from |
|
504 // calling NativeShow(false) excessively on the window which |
|
505 // causes unneeded X traffic. |
|
506 if (!mNeedsShow) { |
|
507 mNeedsShow = true; |
|
508 NativeShow(false); |
|
509 } |
|
510 } |
|
511 } |
|
512 // If the widget hasn't been shown, mark the widget as needing to be |
|
513 // resized before it is shown |
|
514 else if (AreBoundsSane() && mListenForResizes) { |
|
515 // For widgets that we listen for resizes for (widgets created |
|
516 // with native parents) we apparently _always_ have to resize. I |
|
517 // dunno why, but apparently we're lame like that. |
|
518 NativeResize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, |
|
519 aRepaint); |
|
520 } |
|
521 else { |
|
522 mNeedsResize = true; |
|
523 mNeedsMove = true; |
|
524 } |
|
525 |
|
526 if (mIsTopLevel || mListenForResizes) { |
|
527 // synthesize a resize event |
|
528 nsEventStatus status; |
|
529 DispatchResizeEvent(mBounds, status); |
|
530 } |
|
531 |
|
532 if (aRepaint) { |
|
533 mWidget->renderLater(); |
|
534 } |
|
535 |
|
536 NotifyRollupGeometryChange(); |
|
537 return NS_OK; |
|
538 } |
|
539 |
|
540 NS_IMETHODIMP |
|
541 nsWindow::Enable(bool aState) |
|
542 { |
|
543 mEnabled = aState; |
|
544 |
|
545 return NS_OK; |
|
546 } |
|
547 |
|
548 bool |
|
549 nsWindow::IsEnabled() const |
|
550 { |
|
551 return mEnabled; |
|
552 } |
|
553 |
|
554 NS_IMETHODIMP |
|
555 nsWindow::SetFocus(bool aRaise) |
|
556 { |
|
557 // Make sure that our owning widget has focus. If it doesn't try to |
|
558 // grab it. Note that we don't set our focus flag in this case. |
|
559 LOGFOCUS((" SetFocus [%p]\n", (void *)this)); |
|
560 |
|
561 if (!mWidget) { |
|
562 return NS_ERROR_FAILURE; |
|
563 } |
|
564 |
|
565 if (mWidget->focusObject()) { |
|
566 return NS_OK; |
|
567 } |
|
568 |
|
569 // Because QGraphicsItem cannot get the focus if they are |
|
570 // invisible, we look up the chain, for the lowest visible |
|
571 // parent and focus that one |
|
572 QWindow* realFocusItem = nullptr; |
|
573 find_first_visible_parent(mWidget, realFocusItem); |
|
574 |
|
575 if (!realFocusItem || realFocusItem->focusObject()) { |
|
576 return NS_OK; |
|
577 } |
|
578 |
|
579 if (aRaise && mWidget) { |
|
580 // the raising has to happen on the view widget |
|
581 mWidget->raise(); |
|
582 } |
|
583 |
|
584 // XXXndeakin why is this here? It should dispatch only when the OS |
|
585 // notifies us. |
|
586 DispatchActivateEvent(); |
|
587 |
|
588 return NS_OK; |
|
589 } |
|
590 |
|
591 NS_IMETHODIMP |
|
592 nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& aConfigurations) |
|
593 { |
|
594 for (uint32_t i = 0; i < aConfigurations.Length(); ++i) { |
|
595 const Configuration& configuration = aConfigurations[i]; |
|
596 |
|
597 nsWindow* w = static_cast<nsWindow*>(configuration.mChild); |
|
598 NS_ASSERTION(w->GetParent() == this, |
|
599 "Configured widget is not a child"); |
|
600 |
|
601 if (w->mBounds.Size() != configuration.mBounds.Size()) { |
|
602 w->Resize(configuration.mBounds.x, configuration.mBounds.y, |
|
603 configuration.mBounds.width, configuration.mBounds.height, |
|
604 true); |
|
605 } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) { |
|
606 w->Move(configuration.mBounds.x, configuration.mBounds.y); |
|
607 } |
|
608 } |
|
609 return NS_OK; |
|
610 } |
|
611 |
|
612 NS_IMETHODIMP |
|
613 nsWindow::Invalidate(const nsIntRect &aRect) |
|
614 { |
|
615 LOGDRAW(("Invalidate (rect) [%p,%p]: %d %d %d %d\n", (void *)this, |
|
616 (void*)mWidget,aRect.x, aRect.y, aRect.width, aRect.height)); |
|
617 |
|
618 if (!mWidget) { |
|
619 return NS_OK; |
|
620 } |
|
621 |
|
622 mWidget->renderLater(); |
|
623 |
|
624 return NS_OK; |
|
625 } |
|
626 |
|
627 nsIntPoint |
|
628 nsWindow::WidgetToScreenOffset() |
|
629 { |
|
630 NS_ENSURE_TRUE(mWidget, nsIntPoint(0,0)); |
|
631 |
|
632 QPoint origin(0, 0); |
|
633 origin = mWidget->mapToGlobal(origin); |
|
634 |
|
635 return nsIntPoint(origin.x(), origin.y()); |
|
636 } |
|
637 |
|
638 void* |
|
639 nsWindow::GetNativeData(uint32_t aDataType) |
|
640 { |
|
641 switch (aDataType) { |
|
642 case NS_NATIVE_WINDOW: |
|
643 case NS_NATIVE_WIDGET: { |
|
644 return mWidget; |
|
645 } |
|
646 case NS_NATIVE_SHAREABLE_WINDOW: { |
|
647 return mWidget ? (void*)mWidget->winId() : nullptr; |
|
648 } |
|
649 case NS_NATIVE_DISPLAY: { |
|
650 #ifdef MOZ_X11 |
|
651 return gfxQtPlatform::GetXDisplay(mWidget); |
|
652 #endif |
|
653 break; |
|
654 } |
|
655 case NS_NATIVE_PLUGIN_PORT: |
|
656 case NS_NATIVE_GRAPHIC: |
|
657 case NS_NATIVE_SHELLWIDGET: { |
|
658 break; |
|
659 } |
|
660 default: |
|
661 NS_WARNING("nsWindow::GetNativeData called with bad value"); |
|
662 return nullptr; |
|
663 } |
|
664 LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType)); |
|
665 return nullptr; |
|
666 } |
|
667 |
|
668 NS_IMETHODIMP |
|
669 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) |
|
670 { |
|
671 #ifdef DEBUG |
|
672 debug_DumpEvent(stdout, aEvent->widget, aEvent, |
|
673 nsAutoCString("something"), 0); |
|
674 #endif |
|
675 |
|
676 aStatus = nsEventStatus_eIgnore; |
|
677 |
|
678 // send it to the standard callback |
|
679 if (mWidgetListener) { |
|
680 aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents); |
|
681 } |
|
682 |
|
683 return NS_OK; |
|
684 } |
|
685 |
|
686 NS_IMETHODIMP_(void) |
|
687 nsWindow::SetInputContext(const InputContext& aContext, |
|
688 const InputContextAction& aAction) |
|
689 { |
|
690 NS_ENSURE_TRUE_VOID(mWidget); |
|
691 |
|
692 // SetSoftwareKeyboardState uses mInputContext, |
|
693 // so, before calling that, record aContext in mInputContext. |
|
694 mInputContext = aContext; |
|
695 |
|
696 switch (mInputContext.mIMEState.mEnabled) { |
|
697 case IMEState::ENABLED: |
|
698 case IMEState::PASSWORD: |
|
699 case IMEState::PLUGIN: |
|
700 SetSoftwareKeyboardState(true, aAction); |
|
701 break; |
|
702 default: |
|
703 SetSoftwareKeyboardState(false, aAction); |
|
704 break; |
|
705 } |
|
706 } |
|
707 |
|
708 NS_IMETHODIMP_(InputContext) |
|
709 nsWindow::GetInputContext() |
|
710 { |
|
711 mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED; |
|
712 // Our qt widget looks like using only one context per process. |
|
713 // However, it's better to set the context's pointer. |
|
714 mInputContext.mNativeIMEContext = qApp->inputMethod(); |
|
715 |
|
716 return mInputContext; |
|
717 } |
|
718 |
|
719 NS_IMETHODIMP |
|
720 nsWindow::ReparentNativeWidget(nsIWidget *aNewParent) |
|
721 { |
|
722 NS_PRECONDITION(aNewParent, ""); |
|
723 |
|
724 MozQWidget* newParent = static_cast<MozQWidget*>(aNewParent->GetNativeData(NS_NATIVE_WINDOW)); |
|
725 NS_ASSERTION(newParent, "Parent widget has a null native window handle"); |
|
726 if (mWidget) { |
|
727 mWidget->setParent(newParent); |
|
728 } |
|
729 return NS_OK; |
|
730 } |
|
731 |
|
732 NS_IMETHODIMP |
|
733 nsWindow::MakeFullScreen(bool aFullScreen) |
|
734 { |
|
735 NS_ENSURE_TRUE(mWidget, NS_ERROR_FAILURE); |
|
736 |
|
737 if (aFullScreen) { |
|
738 if (mSizeMode != nsSizeMode_Fullscreen) { |
|
739 mLastSizeMode = mSizeMode; |
|
740 } |
|
741 |
|
742 mSizeMode = nsSizeMode_Fullscreen; |
|
743 mWidget->showFullScreen(); |
|
744 } |
|
745 else { |
|
746 mSizeMode = mLastSizeMode; |
|
747 |
|
748 switch (mSizeMode) { |
|
749 case nsSizeMode_Maximized: |
|
750 mWidget->showMaximized(); |
|
751 break; |
|
752 case nsSizeMode_Minimized: |
|
753 mWidget->showMinimized(); |
|
754 break; |
|
755 case nsSizeMode_Normal: |
|
756 mWidget->showNormal(); |
|
757 break; |
|
758 default: |
|
759 mWidget->showNormal(); |
|
760 break; |
|
761 } |
|
762 } |
|
763 |
|
764 NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen, |
|
765 "mLastSizeMode should never be fullscreen"); |
|
766 return nsBaseWidget::MakeFullScreen(aFullScreen); |
|
767 } |
|
768 |
|
769 LayerManager* |
|
770 nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, |
|
771 LayersBackend aBackendHint, |
|
772 LayerManagerPersistence aPersistence, |
|
773 bool* aAllowRetaining) |
|
774 { |
|
775 if (!mLayerManager && eTransparencyTransparent == GetTransparencyMode()) { |
|
776 mLayerManager = CreateBasicLayerManager(); |
|
777 } |
|
778 |
|
779 return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, |
|
780 aPersistence, aAllowRetaining); |
|
781 } |
|
782 |
|
783 void |
|
784 nsWindow::UserActivity() |
|
785 { |
|
786 if (!mIdleService) { |
|
787 mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); |
|
788 } |
|
789 |
|
790 if (mIdleService) { |
|
791 mIdleService->ResetIdleTimeOut(0); |
|
792 } |
|
793 } |
|
794 |
|
795 uint32_t |
|
796 nsWindow::GetGLFrameBufferFormat() |
|
797 { |
|
798 if (mLayerManager && |
|
799 mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { |
|
800 return LOCAL_GL_RGB; |
|
801 } |
|
802 return LOCAL_GL_NONE; |
|
803 } |
|
804 |
|
805 NS_IMETHODIMP |
|
806 nsWindow::SetCursor(nsCursor aCursor) |
|
807 { |
|
808 if (mCursor == aCursor) { |
|
809 return NS_OK; |
|
810 } |
|
811 |
|
812 mCursor = aCursor; |
|
813 if (mWidget) { |
|
814 mWidget->SetCursor(mCursor); |
|
815 } |
|
816 return NS_OK; |
|
817 } |
|
818 |
|
819 NS_IMETHODIMP |
|
820 nsWindow::SetTitle(const nsAString& aTitle) |
|
821 { |
|
822 QString qStr(QString::fromUtf16((const ushort*)aTitle.BeginReading(), aTitle.Length())); |
|
823 |
|
824 mWidget->setTitle(qStr); |
|
825 |
|
826 return NS_OK; |
|
827 } |
|
828 |
|
829 // EVENTS |
|
830 |
|
831 void |
|
832 nsWindow::OnPaint() |
|
833 { |
|
834 LOGDRAW(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this)); |
|
835 nsIWidgetListener* listener = |
|
836 mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener; |
|
837 if (!listener) { |
|
838 return; |
|
839 } |
|
840 |
|
841 listener->WillPaintWindow(this); |
|
842 |
|
843 switch (GetLayerManager()->GetBackendType()) { |
|
844 case mozilla::layers::LayersBackend::LAYERS_CLIENT: { |
|
845 nsIntRegion region(nsIntRect(0, 0, mWidget->width(), mWidget->height())); |
|
846 listener->PaintWindow(this, region); |
|
847 break; |
|
848 } |
|
849 default: |
|
850 NS_ERROR("Invalid layer manager"); |
|
851 } |
|
852 |
|
853 listener->DidPaintWindow(); |
|
854 } |
|
855 |
|
856 nsEventStatus |
|
857 nsWindow::moveEvent(QMoveEvent* aEvent) |
|
858 { |
|
859 LOG(("configure event [%p] %d %d\n", (void *)this, |
|
860 aEvent->pos().x(), aEvent->pos().y())); |
|
861 |
|
862 // can we shortcut? |
|
863 if (!mWidget || !mWidgetListener) |
|
864 return nsEventStatus_eIgnore; |
|
865 |
|
866 if ((mBounds.x == aEvent->pos().x() && |
|
867 mBounds.y == aEvent->pos().y())) |
|
868 { |
|
869 return nsEventStatus_eIgnore; |
|
870 } |
|
871 |
|
872 NotifyWindowMoved(aEvent->pos().x(), aEvent->pos().y()); |
|
873 return nsEventStatus_eConsumeNoDefault; |
|
874 } |
|
875 |
|
876 nsEventStatus |
|
877 nsWindow::resizeEvent(QResizeEvent* aEvent) |
|
878 { |
|
879 nsIntRect rect; |
|
880 |
|
881 // Generate XPFE resize event |
|
882 GetBounds(rect); |
|
883 |
|
884 rect.width = aEvent->size().width(); |
|
885 rect.height = aEvent->size().height(); |
|
886 |
|
887 mBounds.width = rect.width; |
|
888 mBounds.height = rect.height; |
|
889 |
|
890 nsEventStatus status; |
|
891 DispatchResizeEvent(rect, status); |
|
892 return status; |
|
893 } |
|
894 |
|
895 nsEventStatus |
|
896 nsWindow::mouseMoveEvent(QMouseEvent* aEvent) |
|
897 { |
|
898 UserActivity(); |
|
899 |
|
900 mMoveEvent.pos = aEvent->pos(); |
|
901 mMoveEvent.modifiers = aEvent->modifiers(); |
|
902 mMoveEvent.needDispatch = true; |
|
903 DispatchMotionToMainThread(); |
|
904 |
|
905 return nsEventStatus_eIgnore; |
|
906 } |
|
907 |
|
908 nsEventStatus |
|
909 nsWindow::mousePressEvent(QMouseEvent* aEvent) |
|
910 { |
|
911 // The user has done something. |
|
912 UserActivity(); |
|
913 |
|
914 QPoint pos = aEvent->pos(); |
|
915 |
|
916 // we check against the widgets geometry, so use parent coordinates |
|
917 // for the check |
|
918 if (mWidget) |
|
919 pos = mWidget->mapToGlobal(pos); |
|
920 |
|
921 if (CheckForRollup( pos.x(), pos.y(), false)) |
|
922 return nsEventStatus_eIgnore; |
|
923 |
|
924 uint16_t domButton; |
|
925 switch (aEvent->button()) { |
|
926 case Qt::MidButton: |
|
927 domButton = WidgetMouseEvent::eMiddleButton; |
|
928 break; |
|
929 case Qt::RightButton: |
|
930 domButton = WidgetMouseEvent::eRightButton; |
|
931 break; |
|
932 default: |
|
933 domButton = WidgetMouseEvent::eLeftButton; |
|
934 break; |
|
935 } |
|
936 |
|
937 WidgetMouseEvent event(true, NS_MOUSE_BUTTON_DOWN, this, |
|
938 WidgetMouseEvent::eReal); |
|
939 event.button = domButton; |
|
940 InitButtonEvent(event, aEvent, 1); |
|
941 |
|
942 LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton)); |
|
943 |
|
944 nsEventStatus status = DispatchEvent(&event); |
|
945 |
|
946 // right menu click on linux should also pop up a context menu |
|
947 if (domButton == WidgetMouseEvent::eRightButton && |
|
948 MOZ_LIKELY(!mIsDestroyed)) { |
|
949 WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, |
|
950 WidgetMouseEvent::eReal); |
|
951 InitButtonEvent(contextMenuEvent, aEvent, 1); |
|
952 DispatchEvent(&contextMenuEvent, status); |
|
953 } |
|
954 |
|
955 return status; |
|
956 } |
|
957 |
|
958 nsEventStatus |
|
959 nsWindow::mouseReleaseEvent(QMouseEvent* aEvent) |
|
960 { |
|
961 // The user has done something. |
|
962 UserActivity(); |
|
963 |
|
964 uint16_t domButton; |
|
965 |
|
966 switch (aEvent->button()) { |
|
967 case Qt::MidButton: |
|
968 domButton = WidgetMouseEvent::eMiddleButton; |
|
969 break; |
|
970 case Qt::RightButton: |
|
971 domButton = WidgetMouseEvent::eRightButton; |
|
972 break; |
|
973 default: |
|
974 domButton = WidgetMouseEvent::eLeftButton; |
|
975 break; |
|
976 } |
|
977 |
|
978 LOG(("%s [%p] button: %d\n", __PRETTY_FUNCTION__, (void*)this, domButton)); |
|
979 |
|
980 WidgetMouseEvent event(true, NS_MOUSE_BUTTON_UP, this, |
|
981 WidgetMouseEvent::eReal); |
|
982 event.button = domButton; |
|
983 InitButtonEvent(event, aEvent, 1); |
|
984 |
|
985 nsEventStatus status = DispatchEvent(&event); |
|
986 |
|
987 return status; |
|
988 } |
|
989 |
|
990 nsEventStatus |
|
991 nsWindow::mouseDoubleClickEvent(QMouseEvent* aEvent) |
|
992 { |
|
993 uint32_t eventType; |
|
994 |
|
995 switch (aEvent->button()) { |
|
996 case Qt::MidButton: |
|
997 eventType = WidgetMouseEvent::eMiddleButton; |
|
998 break; |
|
999 case Qt::RightButton: |
|
1000 eventType = WidgetMouseEvent::eRightButton; |
|
1001 break; |
|
1002 default: |
|
1003 eventType = WidgetMouseEvent::eLeftButton; |
|
1004 break; |
|
1005 } |
|
1006 |
|
1007 WidgetMouseEvent event(true, NS_MOUSE_DOUBLECLICK, this, |
|
1008 WidgetMouseEvent::eReal); |
|
1009 event.button = eventType; |
|
1010 |
|
1011 InitButtonEvent(event, aEvent, 2); |
|
1012 //pressed |
|
1013 return DispatchEvent(&event); |
|
1014 } |
|
1015 |
|
1016 nsEventStatus |
|
1017 nsWindow::focusInEvent(QFocusEvent* aEvent) |
|
1018 { |
|
1019 LOGFOCUS(("OnFocusInEvent [%p]\n", (void *)this)); |
|
1020 |
|
1021 if (!mWidget) { |
|
1022 return nsEventStatus_eIgnore; |
|
1023 } |
|
1024 |
|
1025 DispatchActivateEventOnTopLevelWindow(); |
|
1026 |
|
1027 LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this)); |
|
1028 return nsEventStatus_eIgnore; |
|
1029 } |
|
1030 |
|
1031 nsEventStatus |
|
1032 nsWindow::focusOutEvent(QFocusEvent* aEvent) |
|
1033 { |
|
1034 LOGFOCUS(("OnFocusOutEvent [%p]\n", (void *)this)); |
|
1035 |
|
1036 if (!mWidget) { |
|
1037 return nsEventStatus_eIgnore; |
|
1038 } |
|
1039 |
|
1040 DispatchDeactivateEventOnTopLevelWindow(); |
|
1041 |
|
1042 LOGFOCUS(("Done with container focus out [%p]\n", (void *)this)); |
|
1043 return nsEventStatus_eIgnore; |
|
1044 } |
|
1045 |
|
1046 nsEventStatus |
|
1047 nsWindow::keyPressEvent(QKeyEvent* aEvent) |
|
1048 { |
|
1049 LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this)); |
|
1050 |
|
1051 // The user has done something. |
|
1052 UserActivity(); |
|
1053 |
|
1054 if (aEvent->key() == Qt::Key_AltGr) { |
|
1055 sAltGrModifier = true; |
|
1056 } |
|
1057 |
|
1058 #ifdef MOZ_X11 |
|
1059 // before we dispatch a key, check if it's the context menu key. |
|
1060 // If so, send a context menu key event instead. |
|
1061 if (isContextMenuKeyEvent(aEvent)) { |
|
1062 WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, |
|
1063 WidgetMouseEvent::eReal, |
|
1064 WidgetMouseEvent::eContextMenuKey); |
|
1065 //keyEventToContextMenuEvent(&event, &contextMenuEvent); |
|
1066 return DispatchEvent(&contextMenuEvent); |
|
1067 } |
|
1068 |
|
1069 uint32_t domCharCode = 0; |
|
1070 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); |
|
1071 |
|
1072 // get keymap and modifier map from the Xserver |
|
1073 Display *display = gfxQtPlatform::GetXDisplay(mWidget); |
|
1074 int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode; |
|
1075 XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode); |
|
1076 XModifierKeymap *xmodmap = XGetModifierMapping(display); |
|
1077 if (!xmodmap) |
|
1078 return nsEventStatus_eIgnore; |
|
1079 |
|
1080 KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode, |
|
1081 &xkeysyms_per_keycode); |
|
1082 if (!xkeymap) { |
|
1083 XFreeModifiermap(xmodmap); |
|
1084 return nsEventStatus_eIgnore; |
|
1085 } |
|
1086 |
|
1087 // create modifier masks |
|
1088 qint32 shift_mask = 0, shift_lock_mask = 0, caps_lock_mask = 0, num_lock_mask = 0; |
|
1089 |
|
1090 for (int i = 0; i < 8 * xmodmap->max_keypermod; ++i) { |
|
1091 qint32 maskbit = 1 << (i / xmodmap->max_keypermod); |
|
1092 KeyCode modkeycode = xmodmap->modifiermap[i]; |
|
1093 if (modkeycode == NoSymbol) { |
|
1094 continue; |
|
1095 } |
|
1096 |
|
1097 quint32 mapindex = (modkeycode - x_min_keycode) * xkeysyms_per_keycode; |
|
1098 for (int j = 0; j < xkeysyms_per_keycode; ++j) { |
|
1099 KeySym modkeysym = xkeymap[mapindex + j]; |
|
1100 switch (modkeysym) { |
|
1101 case XK_Num_Lock: |
|
1102 num_lock_mask |= maskbit; |
|
1103 break; |
|
1104 case XK_Caps_Lock: |
|
1105 caps_lock_mask |= maskbit; |
|
1106 break; |
|
1107 case XK_Shift_Lock: |
|
1108 shift_lock_mask |= maskbit; |
|
1109 break; |
|
1110 case XK_Shift_L: |
|
1111 case XK_Shift_R: |
|
1112 shift_mask |= maskbit; |
|
1113 break; |
|
1114 } |
|
1115 } |
|
1116 } |
|
1117 // indicate whether is down or not |
|
1118 bool shift_state = ((shift_mask & aEvent->nativeModifiers()) != 0) ^ |
|
1119 (bool)(shift_lock_mask & aEvent->nativeModifiers()); |
|
1120 bool capslock_state = (bool)(caps_lock_mask & aEvent->nativeModifiers()); |
|
1121 |
|
1122 // try to find a keysym that we can translate to a DOMKeyCode |
|
1123 // this is needed because some of Qt's keycodes cannot be translated |
|
1124 // TODO: use US keyboard keymap instead of localised keymap |
|
1125 if (!domKeyCode && |
|
1126 aEvent->nativeScanCode() >= (quint32)x_min_keycode && |
|
1127 aEvent->nativeScanCode() <= (quint32)x_max_keycode) { |
|
1128 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; |
|
1129 for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) { |
|
1130 domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]); |
|
1131 } |
|
1132 } |
|
1133 |
|
1134 // store character in domCharCode |
|
1135 if (aEvent->text().length() && aEvent->text()[0].isPrint()) |
|
1136 domCharCode = (int32_t) aEvent->text()[0].unicode(); |
|
1137 |
|
1138 KeyNameIndex keyNameIndex = |
|
1139 domCharCode ? KEY_NAME_INDEX_PrintableKey : |
|
1140 QtKeyCodeToDOMKeyNameIndex(aEvent->key()); |
|
1141 |
|
1142 // If the key isn't autorepeat, we need to send the initial down event |
|
1143 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) { |
|
1144 // send the key down event |
|
1145 |
|
1146 SetKeyDownFlag(domKeyCode); |
|
1147 |
|
1148 WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this); |
|
1149 InitKeyEvent(downEvent, aEvent); |
|
1150 |
|
1151 downEvent.keyCode = domKeyCode; |
|
1152 downEvent.mKeyNameIndex = keyNameIndex; |
|
1153 |
|
1154 nsEventStatus status = DispatchEvent(&downEvent); |
|
1155 |
|
1156 // DispatchEvent can Destroy us (bug 378273) |
|
1157 if (MOZ_UNLIKELY(mIsDestroyed)) { |
|
1158 qWarning() << "Returning[" << __LINE__ << "]: " << "Window destroyed"; |
|
1159 return status; |
|
1160 } |
|
1161 |
|
1162 // If prevent default on keydown, don't dispatch keypress event |
|
1163 if (status == nsEventStatus_eConsumeNoDefault) { |
|
1164 return nsEventStatus_eConsumeNoDefault; |
|
1165 } |
|
1166 } |
|
1167 |
|
1168 // Don't pass modifiers as NS_KEY_PRESS events. |
|
1169 // Instead of selectively excluding some keys from NS_KEY_PRESS events, |
|
1170 // we instead selectively include (as per MSDN spec |
|
1171 // ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress%28VS.71%29.aspx ); |
|
1172 // no official spec covers KeyPress events). |
|
1173 if (aEvent->key() == Qt::Key_Shift || |
|
1174 aEvent->key() == Qt::Key_Control || |
|
1175 aEvent->key() == Qt::Key_Meta || |
|
1176 aEvent->key() == Qt::Key_Alt || |
|
1177 aEvent->key() == Qt::Key_AltGr) { |
|
1178 |
|
1179 return nsEventStatus_eIgnore; |
|
1180 } |
|
1181 |
|
1182 // Look for specialized app-command keys |
|
1183 switch (aEvent->key()) { |
|
1184 case Qt::Key_Back: |
|
1185 return DispatchCommandEvent(nsGkAtoms::Back); |
|
1186 case Qt::Key_Forward: |
|
1187 return DispatchCommandEvent(nsGkAtoms::Forward); |
|
1188 case Qt::Key_Refresh: |
|
1189 return DispatchCommandEvent(nsGkAtoms::Reload); |
|
1190 case Qt::Key_Stop: |
|
1191 return DispatchCommandEvent(nsGkAtoms::Stop); |
|
1192 case Qt::Key_Search: |
|
1193 return DispatchCommandEvent(nsGkAtoms::Search); |
|
1194 case Qt::Key_Favorites: |
|
1195 return DispatchCommandEvent(nsGkAtoms::Bookmarks); |
|
1196 case Qt::Key_HomePage: |
|
1197 return DispatchCommandEvent(nsGkAtoms::Home); |
|
1198 case Qt::Key_Copy: |
|
1199 case Qt::Key_F16: // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo |
|
1200 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_COPY); |
|
1201 case Qt::Key_Cut: |
|
1202 case Qt::Key_F20: |
|
1203 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_CUT); |
|
1204 case Qt::Key_Paste: |
|
1205 case Qt::Key_F18: |
|
1206 case Qt::Key_F9: |
|
1207 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_PASTE); |
|
1208 case Qt::Key_F14: |
|
1209 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO); |
|
1210 } |
|
1211 |
|
1212 // Qt::Key_Redo and Qt::Key_Undo are not available yet. |
|
1213 if (aEvent->nativeVirtualKey() == 0xff66) { |
|
1214 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_REDO); |
|
1215 } |
|
1216 if (aEvent->nativeVirtualKey() == 0xff65) { |
|
1217 return DispatchContentCommandEvent(NS_CONTENT_COMMAND_UNDO); |
|
1218 } |
|
1219 |
|
1220 WidgetKeyboardEvent event(true, NS_KEY_PRESS, this); |
|
1221 InitKeyEvent(event, aEvent); |
|
1222 |
|
1223 // If there is no charcode attainable from the text, try to |
|
1224 // generate it from the keycode. Check shift state for case |
|
1225 // Also replace the charcode if ControlModifier is the only |
|
1226 // pressed Modifier |
|
1227 if ((!domCharCode) && |
|
1228 (QGuiApplication::keyboardModifiers() & |
|
1229 (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { |
|
1230 |
|
1231 // get a character from X11 key map |
|
1232 KeySym keysym = aEvent->nativeVirtualKey(); |
|
1233 if (keysym) { |
|
1234 domCharCode = (uint32_t) keysym2ucs(keysym); |
|
1235 if (domCharCode == -1 || !QChar((quint32)domCharCode).isPrint()) { |
|
1236 domCharCode = 0; |
|
1237 } |
|
1238 } |
|
1239 |
|
1240 // if Ctrl is pressed and domCharCode is not a ASCII character |
|
1241 if (domCharCode > 0xFF && (QGuiApplication::keyboardModifiers() & Qt::ControlModifier)) { |
|
1242 // replace Unicode character |
|
1243 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; |
|
1244 for (int i = 0; i < xkeysyms_per_keycode; ++i) { |
|
1245 if (xkeymap[index + i] <= 0xFF && !shift_state) { |
|
1246 domCharCode = (uint32_t) QChar::toLower((uint) xkeymap[index + i]); |
|
1247 break; |
|
1248 } |
|
1249 } |
|
1250 } |
|
1251 |
|
1252 } else { // The key event should cause a character input. |
|
1253 // At that time, we need to reset the modifiers |
|
1254 // because nsEditor will not accept a key event |
|
1255 // for text input if one or more modifiers are set. |
|
1256 event.modifiers &= ~(MODIFIER_CONTROL | |
|
1257 MODIFIER_ALT | |
|
1258 MODIFIER_META); |
|
1259 } |
|
1260 |
|
1261 KeySym keysym = NoSymbol; |
|
1262 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; |
|
1263 for (int i = 0; i < xkeysyms_per_keycode; ++i) { |
|
1264 if (xkeymap[index + i] == aEvent->nativeVirtualKey()) { |
|
1265 if ((i % 2) == 0) { // shifted char |
|
1266 keysym = xkeymap[index + i + 1]; |
|
1267 break; |
|
1268 } else { // unshifted char |
|
1269 keysym = xkeymap[index + i - 1]; |
|
1270 break; |
|
1271 } |
|
1272 } |
|
1273 if (xkeysyms_per_keycode - 1 == i) { |
|
1274 qWarning() << "Symbol '" << aEvent->nativeVirtualKey() << "' not found"; |
|
1275 } |
|
1276 } |
|
1277 QChar unshiftedChar(domCharCode); |
|
1278 long ucs = keysym2ucs(keysym); |
|
1279 ucs = ucs == -1 ? 0 : ucs; |
|
1280 QChar shiftedChar((uint)ucs); |
|
1281 |
|
1282 // append alternativeCharCodes if modifier is pressed |
|
1283 // append an additional alternativeCharCodes if domCharCode is not a Latin character |
|
1284 // and if one of these modifiers is pressed (i.e. Ctrl, Alt, Meta) |
|
1285 if (domCharCode && |
|
1286 (QGuiApplication::keyboardModifiers() & |
|
1287 (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { |
|
1288 |
|
1289 event.charCode = domCharCode; |
|
1290 event.keyCode = 0; |
|
1291 AlternativeCharCode altCharCode(0, 0); |
|
1292 // if character has a lower and upper representation |
|
1293 if ((unshiftedChar.isUpper() || unshiftedChar.isLower()) && |
|
1294 unshiftedChar.toLower() == shiftedChar.toLower()) { |
|
1295 if (shift_state ^ capslock_state) { |
|
1296 altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode); |
|
1297 altCharCode.mShiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode); |
|
1298 } else { |
|
1299 altCharCode.mUnshiftedCharCode = (uint32_t) QChar::toLower((uint)domCharCode); |
|
1300 altCharCode.mShiftedCharCode = (uint32_t) QChar::toUpper((uint)domCharCode); |
|
1301 } |
|
1302 } else { |
|
1303 altCharCode.mUnshiftedCharCode = (uint32_t) unshiftedChar.unicode(); |
|
1304 altCharCode.mShiftedCharCode = (uint32_t) shiftedChar.unicode(); |
|
1305 } |
|
1306 |
|
1307 // append alternative char code to event |
|
1308 if ((altCharCode.mUnshiftedCharCode && altCharCode.mUnshiftedCharCode != domCharCode) || |
|
1309 (altCharCode.mShiftedCharCode && altCharCode.mShiftedCharCode != domCharCode)) { |
|
1310 event.alternativeCharCodes.AppendElement(altCharCode); |
|
1311 } |
|
1312 |
|
1313 // check if the alternative char codes are latin-1 |
|
1314 if (altCharCode.mUnshiftedCharCode > 0xFF || altCharCode.mShiftedCharCode > 0xFF) { |
|
1315 altCharCode.mUnshiftedCharCode = altCharCode.mShiftedCharCode = 0; |
|
1316 |
|
1317 // find latin char for keycode |
|
1318 KeySym keysym = NoSymbol; |
|
1319 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; |
|
1320 // find first shifted and unshifted Latin-Char in XKeyMap |
|
1321 for (int i = 0; i < xkeysyms_per_keycode; ++i) { |
|
1322 keysym = xkeymap[index + i]; |
|
1323 if (keysym && keysym <= 0xFF) { |
|
1324 if ((shift_state && (i % 2 == 1)) || |
|
1325 (!shift_state && (i % 2 == 0))) { |
|
1326 altCharCode.mUnshiftedCharCode = altCharCode.mUnshiftedCharCode ? |
|
1327 altCharCode.mUnshiftedCharCode : |
|
1328 keysym; |
|
1329 } else { |
|
1330 altCharCode.mShiftedCharCode = altCharCode.mShiftedCharCode ? |
|
1331 altCharCode.mShiftedCharCode : |
|
1332 keysym; |
|
1333 } |
|
1334 if (altCharCode.mUnshiftedCharCode && altCharCode.mShiftedCharCode) { |
|
1335 break; |
|
1336 } |
|
1337 } |
|
1338 } |
|
1339 |
|
1340 if (altCharCode.mUnshiftedCharCode || altCharCode.mShiftedCharCode) { |
|
1341 event.alternativeCharCodes.AppendElement(altCharCode); |
|
1342 } |
|
1343 } |
|
1344 } else { |
|
1345 event.charCode = domCharCode; |
|
1346 } |
|
1347 |
|
1348 if (xmodmap) { |
|
1349 XFreeModifiermap(xmodmap); |
|
1350 } |
|
1351 if (xkeymap) { |
|
1352 XFree(xkeymap); |
|
1353 } |
|
1354 |
|
1355 event.keyCode = domCharCode ? 0 : domKeyCode; |
|
1356 event.mKeyNameIndex = keyNameIndex; |
|
1357 // send the key press event |
|
1358 return DispatchEvent(&event); |
|
1359 #else |
|
1360 |
|
1361 //:TODO: fix shortcuts hebrew for non X11, |
|
1362 //see Bug 562195##51 |
|
1363 |
|
1364 // before we dispatch a key, check if it's the context menu key. |
|
1365 // If so, send a context menu key event instead. |
|
1366 if (isContextMenuKeyEvent(aEvent)) { |
|
1367 WidgetMouseEvent contextMenuEvent(true, NS_CONTEXTMENU, this, |
|
1368 WidgetMouseEvent::eReal, |
|
1369 WidgetMouseEvent::eContextMenuKey); |
|
1370 //keyEventToContextMenuEvent(&event, &contextMenuEvent); |
|
1371 return DispatchEvent(&contextMenuEvent); |
|
1372 } |
|
1373 |
|
1374 uint32_t domCharCode = 0; |
|
1375 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); |
|
1376 |
|
1377 if (aEvent->text().length() && aEvent->text()[0].isPrint()) { |
|
1378 domCharCode = (int32_t) aEvent->text()[0].unicode(); |
|
1379 } |
|
1380 |
|
1381 KeyNameIndex keyNameIndex = |
|
1382 domCharCode ? KEY_NAME_INDEX_PrintableKey : |
|
1383 QtKeyCodeToDOMKeyNameIndex(aEvent->key()); |
|
1384 |
|
1385 // If the key isn't autorepeat, we need to send the initial down event |
|
1386 if (!aEvent->isAutoRepeat() && !IsKeyDown(domKeyCode)) { |
|
1387 // send the key down event |
|
1388 |
|
1389 SetKeyDownFlag(domKeyCode); |
|
1390 |
|
1391 WidgetKeyboardEvent downEvent(true, NS_KEY_DOWN, this); |
|
1392 InitKeyEvent(downEvent, aEvent); |
|
1393 |
|
1394 downEvent.keyCode = domKeyCode; |
|
1395 downEvent.mKeyNameIndex = keyNameIndex; |
|
1396 |
|
1397 nsEventStatus status = DispatchEvent(&downEvent); |
|
1398 |
|
1399 // If prevent default on keydown, don't dispatch keypress event |
|
1400 if (status == nsEventStatus_eConsumeNoDefault) { |
|
1401 return nsEventStatus_eConsumeNoDefault; |
|
1402 } |
|
1403 } |
|
1404 |
|
1405 WidgetKeyboardEvent event(true, NS_KEY_PRESS, this); |
|
1406 InitKeyEvent(event, aEvent); |
|
1407 |
|
1408 event.charCode = domCharCode; |
|
1409 |
|
1410 event.keyCode = domCharCode ? 0 : domKeyCode; |
|
1411 event.mKeyNameIndex = keyNameIndex; |
|
1412 |
|
1413 // send the key press event |
|
1414 return DispatchEvent(&event); |
|
1415 #endif |
|
1416 } |
|
1417 |
|
1418 nsEventStatus |
|
1419 nsWindow::keyReleaseEvent(QKeyEvent* aEvent) |
|
1420 { |
|
1421 LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this)); |
|
1422 |
|
1423 // The user has done something. |
|
1424 UserActivity(); |
|
1425 |
|
1426 if (isContextMenuKeyEvent(aEvent)) { |
|
1427 // er, what do we do here? DoDefault or NoDefault? |
|
1428 return nsEventStatus_eConsumeDoDefault; |
|
1429 } |
|
1430 |
|
1431 uint32_t domKeyCode = QtKeyCodeToDOMKeyCode(aEvent->key()); |
|
1432 |
|
1433 #ifdef MOZ_X11 |
|
1434 if (!domKeyCode) { |
|
1435 // get keymap from the Xserver |
|
1436 Display *display = gfxQtPlatform::GetXDisplay(mWidget); |
|
1437 int x_min_keycode = 0, x_max_keycode = 0, xkeysyms_per_keycode; |
|
1438 XDisplayKeycodes(display, &x_min_keycode, &x_max_keycode); |
|
1439 KeySym *xkeymap = XGetKeyboardMapping(display, x_min_keycode, x_max_keycode - x_min_keycode, |
|
1440 &xkeysyms_per_keycode); |
|
1441 |
|
1442 if (aEvent->nativeScanCode() >= (quint32)x_min_keycode && |
|
1443 aEvent->nativeScanCode() <= (quint32)x_max_keycode) { |
|
1444 int index = (aEvent->nativeScanCode() - x_min_keycode) * xkeysyms_per_keycode; |
|
1445 for(int i = 0; (i < xkeysyms_per_keycode) && (domKeyCode == (quint32)NoSymbol); ++i) { |
|
1446 domKeyCode = QtKeyCodeToDOMKeyCode(xkeymap[index + i]); |
|
1447 } |
|
1448 } |
|
1449 |
|
1450 if (xkeymap) { |
|
1451 XFree(xkeymap); |
|
1452 } |
|
1453 } |
|
1454 #endif // MOZ_X11 |
|
1455 |
|
1456 // send the key event as a key up event |
|
1457 WidgetKeyboardEvent event(true, NS_KEY_UP, this); |
|
1458 InitKeyEvent(event, aEvent); |
|
1459 |
|
1460 if (aEvent->key() == Qt::Key_AltGr) { |
|
1461 sAltGrModifier = false; |
|
1462 } |
|
1463 |
|
1464 event.keyCode = domKeyCode; |
|
1465 event.mKeyNameIndex = |
|
1466 (aEvent->text().length() && aEvent->text()[0].isPrint()) ? |
|
1467 KEY_NAME_INDEX_PrintableKey : |
|
1468 QtKeyCodeToDOMKeyNameIndex(aEvent->key()); |
|
1469 |
|
1470 // unset the key down flag |
|
1471 ClearKeyDownFlag(event.keyCode); |
|
1472 |
|
1473 return DispatchEvent(&event); |
|
1474 } |
|
1475 |
|
1476 nsEventStatus |
|
1477 nsWindow::wheelEvent(QWheelEvent* aEvent) |
|
1478 { |
|
1479 // check to see if we should rollup |
|
1480 WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this); |
|
1481 wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE; |
|
1482 |
|
1483 // negative values for aEvent->delta indicate downward scrolling; |
|
1484 // this is opposite Gecko usage. |
|
1485 // TODO: Store the unused delta values due to fraction round and add it |
|
1486 // to next event. The stored values should be reset by other |
|
1487 // direction scroll event. |
|
1488 int32_t delta = (int)(aEvent->delta() / WHEEL_DELTA) * -3; |
|
1489 |
|
1490 switch (aEvent->orientation()) { |
|
1491 case Qt::Vertical: |
|
1492 wheelEvent.deltaY = wheelEvent.lineOrPageDeltaY = delta; |
|
1493 break; |
|
1494 case Qt::Horizontal: |
|
1495 wheelEvent.deltaX = wheelEvent.lineOrPageDeltaX = delta; |
|
1496 break; |
|
1497 default: |
|
1498 Q_ASSERT(0); |
|
1499 break; |
|
1500 } |
|
1501 |
|
1502 wheelEvent.refPoint.x = nscoord(aEvent->pos().x()); |
|
1503 wheelEvent.refPoint.y = nscoord(aEvent->pos().y()); |
|
1504 |
|
1505 wheelEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier, |
|
1506 aEvent->modifiers() & Qt::AltModifier, |
|
1507 aEvent->modifiers() & Qt::ShiftModifier, |
|
1508 aEvent->modifiers() & Qt::MetaModifier); |
|
1509 wheelEvent.time = 0; |
|
1510 |
|
1511 return DispatchEvent(&wheelEvent); |
|
1512 } |
|
1513 |
|
1514 nsEventStatus |
|
1515 nsWindow::showEvent(QShowEvent *) |
|
1516 { |
|
1517 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this)); |
|
1518 mVisible = true; |
|
1519 return nsEventStatus_eConsumeDoDefault; |
|
1520 } |
|
1521 |
|
1522 nsEventStatus |
|
1523 nsWindow::hideEvent(QHideEvent *) |
|
1524 { |
|
1525 LOG(("%s [%p]\n", __PRETTY_FUNCTION__,(void *)this)); |
|
1526 mVisible = false; |
|
1527 return nsEventStatus_eConsumeDoDefault; |
|
1528 } |
|
1529 |
|
1530 nsEventStatus nsWindow::touchEvent(QTouchEvent* aEvent) |
|
1531 { |
|
1532 return nsEventStatus_eIgnore; |
|
1533 } |
|
1534 |
|
1535 nsEventStatus |
|
1536 nsWindow::tabletEvent(QTabletEvent* aEvent) |
|
1537 { |
|
1538 LOGFOCUS(("nsWindow::%s [%p]\n", __FUNCTION__, (void *)this)); |
|
1539 return nsEventStatus_eIgnore; |
|
1540 } |
|
1541 |
|
1542 // Helpers |
|
1543 |
|
1544 void |
|
1545 nsWindow::InitButtonEvent(WidgetMouseEvent& aMoveEvent, |
|
1546 QMouseEvent* aEvent, |
|
1547 int aClickCount) |
|
1548 { |
|
1549 aMoveEvent.refPoint.x = nscoord(aEvent->pos().x()); |
|
1550 aMoveEvent.refPoint.y = nscoord(aEvent->pos().y()); |
|
1551 |
|
1552 aMoveEvent.InitBasicModifiers(aEvent->modifiers() & Qt::ControlModifier, |
|
1553 aEvent->modifiers() & Qt::AltModifier, |
|
1554 aEvent->modifiers() & Qt::ShiftModifier, |
|
1555 aEvent->modifiers() & Qt::MetaModifier); |
|
1556 aMoveEvent.clickCount = aClickCount; |
|
1557 } |
|
1558 |
|
1559 nsEventStatus |
|
1560 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent) |
|
1561 { |
|
1562 nsEventStatus status; |
|
1563 DispatchEvent(aEvent, status); |
|
1564 return status; |
|
1565 } |
|
1566 |
|
1567 void |
|
1568 nsWindow::DispatchActivateEvent(void) |
|
1569 { |
|
1570 if (mWidgetListener) { |
|
1571 mWidgetListener->WindowActivated(); |
|
1572 } |
|
1573 } |
|
1574 |
|
1575 void |
|
1576 nsWindow::DispatchDeactivateEvent(void) |
|
1577 { |
|
1578 if (mWidgetListener) { |
|
1579 mWidgetListener->WindowDeactivated(); |
|
1580 } |
|
1581 } |
|
1582 |
|
1583 void |
|
1584 nsWindow::DispatchActivateEventOnTopLevelWindow(void) |
|
1585 { |
|
1586 nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget()); |
|
1587 if (topLevelWindow != nullptr) { |
|
1588 topLevelWindow->DispatchActivateEvent(); |
|
1589 } |
|
1590 } |
|
1591 |
|
1592 void |
|
1593 nsWindow::DispatchDeactivateEventOnTopLevelWindow(void) |
|
1594 { |
|
1595 nsWindow* topLevelWindow = static_cast<nsWindow*>(GetTopLevelWidget()); |
|
1596 if (topLevelWindow != nullptr) { |
|
1597 topLevelWindow->DispatchDeactivateEvent(); |
|
1598 } |
|
1599 } |
|
1600 |
|
1601 void |
|
1602 nsWindow::DispatchResizeEvent(nsIntRect &aRect, nsEventStatus &aStatus) |
|
1603 { |
|
1604 aStatus = nsEventStatus_eIgnore; |
|
1605 if (mWidgetListener && |
|
1606 mWidgetListener->WindowResized(this, aRect.width, aRect.height)) { |
|
1607 aStatus = nsEventStatus_eConsumeNoDefault; |
|
1608 } |
|
1609 } |
|
1610 |
|
1611 ///////////////////////////////////// OLD GECKO ECENTS need to Sort /////////////////// |
|
1612 |
|
1613 /* static */ bool |
|
1614 isContextMenuKeyEvent(const QKeyEvent *qe) |
|
1615 { |
|
1616 uint32_t kc = QtKeyCodeToDOMKeyCode(qe->key()); |
|
1617 if (qe->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) { |
|
1618 return false; |
|
1619 } |
|
1620 |
|
1621 bool isShift = qe->modifiers() & Qt::ShiftModifier; |
|
1622 return (kc == NS_VK_F10 && isShift) || |
|
1623 (kc == NS_VK_CONTEXT_MENU && !isShift); |
|
1624 } |
|
1625 |
|
1626 /* static */void |
|
1627 InitKeyEvent(WidgetKeyboardEvent &aEvent, QKeyEvent *aQEvent) |
|
1628 { |
|
1629 aEvent.InitBasicModifiers(aQEvent->modifiers() & Qt::ControlModifier, |
|
1630 aQEvent->modifiers() & Qt::AltModifier, |
|
1631 aQEvent->modifiers() & Qt::ShiftModifier, |
|
1632 aQEvent->modifiers() & Qt::MetaModifier); |
|
1633 aEvent.mIsRepeat = |
|
1634 (aEvent.message == NS_KEY_DOWN || aEvent.message == NS_KEY_PRESS) && |
|
1635 aQEvent->isAutoRepeat(); |
|
1636 aEvent.time = 0; |
|
1637 |
|
1638 if (sAltGrModifier) { |
|
1639 aEvent.modifiers |= (MODIFIER_CONTROL | MODIFIER_ALT); |
|
1640 } |
|
1641 |
|
1642 // The transformations above and in qt for the keyval are not invertible |
|
1643 // so link to the QKeyEvent (which will vanish soon after return from the |
|
1644 // event callback) to give plugins access to hardware_keycode and state. |
|
1645 // (An XEvent would be nice but the QKeyEvent is good enough.) |
|
1646 aEvent.pluginEvent = (void *)aQEvent; |
|
1647 } |
|
1648 |
|
1649 NS_IMPL_ISUPPORTS_INHERITED(nsWindow, nsBaseWidget, nsISupportsWeakReference) |
|
1650 |
|
1651 |
|
1652 |
|
1653 void |
|
1654 nsWindow::ClearCachedResources() |
|
1655 { |
|
1656 if (mLayerManager && |
|
1657 mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) { |
|
1658 mLayerManager->ClearCachedResources(); |
|
1659 } |
|
1660 for (nsIWidget* kid = mFirstChild; kid; ) { |
|
1661 nsIWidget* next = kid->GetNextSibling(); |
|
1662 static_cast<nsWindow*>(kid)->ClearCachedResources(); |
|
1663 kid = next; |
|
1664 } |
|
1665 } |
|
1666 |
|
1667 NS_IMETHODIMP |
|
1668 nsWindow::SetParent(nsIWidget *aNewParent) |
|
1669 { |
|
1670 NS_ENSURE_ARG_POINTER(aNewParent); |
|
1671 |
|
1672 nsCOMPtr<nsIWidget> kungFuDeathGrip(this); |
|
1673 nsIWidget* parent = GetParent(); |
|
1674 if (parent) { |
|
1675 parent->RemoveChild(this); |
|
1676 } |
|
1677 ReparentNativeWidget(aNewParent); |
|
1678 aNewParent->AddChild(this); |
|
1679 return NS_OK; |
|
1680 } |
|
1681 |
|
1682 NS_IMETHODIMP |
|
1683 nsWindow::SetModal(bool aModal) |
|
1684 { |
|
1685 LOG(("nsWindow::SetModal [%p] %d, widget[%p]\n", (void *)this, aModal, mWidget)); |
|
1686 if (mWidget) { |
|
1687 mWidget->setModality(aModal ? Qt::WindowModal : Qt::NonModal); |
|
1688 } |
|
1689 |
|
1690 return NS_OK; |
|
1691 } |
|
1692 |
|
1693 |
|
1694 NS_IMETHODIMP |
|
1695 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, |
|
1696 nsIWidget *aWidget, |
|
1697 bool aActivate) |
|
1698 { |
|
1699 return NS_ERROR_NOT_IMPLEMENTED; |
|
1700 } |
|
1701 |
|
1702 NS_IMETHODIMP |
|
1703 nsWindow::SetSizeMode(int32_t aMode) |
|
1704 { |
|
1705 nsresult rv; |
|
1706 |
|
1707 LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode)); |
|
1708 if (aMode != nsSizeMode_Minimized) { |
|
1709 mWidget->requestActivate(); |
|
1710 } |
|
1711 |
|
1712 // Save the requested state. |
|
1713 rv = nsBaseWidget::SetSizeMode(aMode); |
|
1714 |
|
1715 // return if there's no shell or our current state is the same as |
|
1716 // the mode we were just set to. |
|
1717 if (!mWidget || mSizeState == mSizeMode) { |
|
1718 return rv; |
|
1719 } |
|
1720 |
|
1721 switch (aMode) { |
|
1722 case nsSizeMode_Maximized: |
|
1723 mWidget->showMaximized(); |
|
1724 break; |
|
1725 case nsSizeMode_Minimized: |
|
1726 mWidget->showMinimized(); |
|
1727 break; |
|
1728 case nsSizeMode_Fullscreen: |
|
1729 mWidget->showFullScreen(); |
|
1730 break; |
|
1731 |
|
1732 default: |
|
1733 // nsSizeMode_Normal, really. |
|
1734 mWidget->show(); |
|
1735 break; |
|
1736 } |
|
1737 |
|
1738 mSizeState = mSizeMode; |
|
1739 |
|
1740 return rv; |
|
1741 } |
|
1742 |
|
1743 // Helper function to recursively find the first parent item that |
|
1744 // is still visible (QGraphicsItem can be hidden even if they are |
|
1745 // set to visible if one of their ancestors is invisible) |
|
1746 /* static */ |
|
1747 void find_first_visible_parent(QWindow* aItem, QWindow*& aVisibleItem) |
|
1748 { |
|
1749 NS_ENSURE_TRUE_VOID(aItem); |
|
1750 |
|
1751 aVisibleItem = nullptr; |
|
1752 QWindow* parItem = nullptr; |
|
1753 while (!aVisibleItem) { |
|
1754 if (aItem->isVisible()) { |
|
1755 aVisibleItem = aItem; |
|
1756 } |
|
1757 else { |
|
1758 parItem = aItem->parent(); |
|
1759 if (parItem) { |
|
1760 aItem = parItem; |
|
1761 } |
|
1762 else { |
|
1763 aItem->setVisible(true); |
|
1764 aVisibleItem = aItem; |
|
1765 } |
|
1766 } |
|
1767 } |
|
1768 } |
|
1769 |
|
1770 NS_IMETHODIMP |
|
1771 nsWindow::GetScreenBounds(nsIntRect &aRect) |
|
1772 { |
|
1773 aRect = nsIntRect(nsIntPoint(0, 0), mBounds.Size()); |
|
1774 if (mIsTopLevel) { |
|
1775 QPoint pos = mWidget->position(); |
|
1776 aRect.MoveTo(pos.x(), pos.y()); |
|
1777 } |
|
1778 else { |
|
1779 aRect.MoveTo(WidgetToScreenOffset()); |
|
1780 } |
|
1781 LOG(("GetScreenBounds %d %d | %d %d | %d %d\n", |
|
1782 aRect.x, aRect.y, |
|
1783 mBounds.width, mBounds.height, |
|
1784 aRect.width, aRect.height)); |
|
1785 return NS_OK; |
|
1786 } |
|
1787 |
|
1788 NS_IMETHODIMP |
|
1789 nsWindow::SetIcon(const nsAString& aIconSpec) |
|
1790 { |
|
1791 if (!mWidget) |
|
1792 return NS_OK; |
|
1793 |
|
1794 nsCOMPtr<nsIFile> iconFile; |
|
1795 nsAutoCString path; |
|
1796 nsTArray<nsCString> iconList; |
|
1797 |
|
1798 // Look for icons with the following suffixes appended to the base name. |
|
1799 // The last two entries (for the old XPM format) will be ignored unless |
|
1800 // no icons are found using the other suffixes. XPM icons are depricated. |
|
1801 |
|
1802 const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png", |
|
1803 ".xpm", "16.xpm" }; |
|
1804 |
|
1805 for (uint32_t i = 0; i < ArrayLength(extensions); i++) { |
|
1806 // Don't bother looking for XPM versions if we found a PNG. |
|
1807 if (i == ArrayLength(extensions) - 2 && iconList.Length()) |
|
1808 break; |
|
1809 |
|
1810 nsAutoString extension; |
|
1811 extension.AppendASCII(extensions[i]); |
|
1812 |
|
1813 ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile)); |
|
1814 if (iconFile) { |
|
1815 iconFile->GetNativePath(path); |
|
1816 iconList.AppendElement(path); |
|
1817 } |
|
1818 } |
|
1819 |
|
1820 // leave the default icon intact if no matching icons were found |
|
1821 if (iconList.Length() == 0) |
|
1822 return NS_OK; |
|
1823 |
|
1824 return SetWindowIconList(iconList); |
|
1825 } |
|
1826 |
|
1827 NS_IMETHODIMP |
|
1828 nsWindow::CaptureMouse(bool aCapture) |
|
1829 { |
|
1830 LOG(("CaptureMouse %p\n", (void *)this)); |
|
1831 |
|
1832 if (!mWidget) |
|
1833 return NS_OK; |
|
1834 |
|
1835 mWidget->setMouseGrabEnabled(aCapture); |
|
1836 |
|
1837 return NS_OK; |
|
1838 } |
|
1839 |
|
1840 bool |
|
1841 nsWindow::CheckForRollup(double aMouseX, double aMouseY, |
|
1842 bool aIsWheel) |
|
1843 { |
|
1844 nsIRollupListener* rollupListener = GetActiveRollupListener(); |
|
1845 nsCOMPtr<nsIWidget> rollupWidget; |
|
1846 if (rollupListener) { |
|
1847 rollupWidget = rollupListener->GetRollupWidget(); |
|
1848 } |
|
1849 if (!rollupWidget) { |
|
1850 nsBaseWidget::gRollupListener = nullptr; |
|
1851 return false; |
|
1852 } |
|
1853 |
|
1854 bool retVal = false; |
|
1855 MozQWidget *currentPopup = |
|
1856 (MozQWidget *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW); |
|
1857 if (!is_mouse_in_window(currentPopup, aMouseX, aMouseY)) { |
|
1858 bool rollup = true; |
|
1859 if (aIsWheel) { |
|
1860 rollup = rollupListener->ShouldRollupOnMouseWheelEvent(); |
|
1861 retVal = true; |
|
1862 } |
|
1863 // if we're dealing with menus, we probably have submenus and |
|
1864 // we don't want to rollup if the clickis in a parent menu of |
|
1865 // the current submenu |
|
1866 uint32_t popupsToRollup = UINT32_MAX; |
|
1867 if (rollupListener) { |
|
1868 nsAutoTArray<nsIWidget*, 5> widgetChain; |
|
1869 uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain); |
|
1870 for (uint32_t i=0; i<widgetChain.Length(); ++i) { |
|
1871 nsIWidget* widget = widgetChain[i]; |
|
1872 MozQWidget* currWindow = |
|
1873 (MozQWidget*) widget->GetNativeData(NS_NATIVE_WINDOW); |
|
1874 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) { |
|
1875 if (i < sameTypeCount) { |
|
1876 rollup = false; |
|
1877 } |
|
1878 else { |
|
1879 popupsToRollup = sameTypeCount; |
|
1880 } |
|
1881 break; |
|
1882 } |
|
1883 } // foreach parent menu widget |
|
1884 } // if rollup listener knows about menus |
|
1885 |
|
1886 // if we've determined that we should still rollup, do it. |
|
1887 if (rollup) { |
|
1888 nsIntPoint pos(aMouseX, aMouseY); |
|
1889 retVal = rollupListener->Rollup(popupsToRollup, &pos, nullptr); |
|
1890 } |
|
1891 } |
|
1892 |
|
1893 return retVal; |
|
1894 } |
|
1895 |
|
1896 /* static */ |
|
1897 bool |
|
1898 is_mouse_in_window (MozQWidget* aWindow, double aMouseX, double aMouseY) |
|
1899 { |
|
1900 return aWindow->geometry().contains(aMouseX, aMouseY); |
|
1901 } |
|
1902 |
|
1903 NS_IMETHODIMP |
|
1904 nsWindow::GetAttention(int32_t aCycleCount) |
|
1905 { |
|
1906 LOG(("nsWindow::GetAttention [%p]\n", (void *)this)); |
|
1907 return NS_ERROR_NOT_IMPLEMENTED; |
|
1908 } |
|
1909 |
|
1910 |
|
1911 |
|
1912 nsEventStatus |
|
1913 nsWindow::OnCloseEvent(QCloseEvent *aEvent) |
|
1914 { |
|
1915 if (!mWidgetListener) |
|
1916 return nsEventStatus_eIgnore; |
|
1917 mWidgetListener->RequestWindowClose(this); |
|
1918 return nsEventStatus_eConsumeNoDefault; |
|
1919 } |
|
1920 |
|
1921 |
|
1922 inline bool |
|
1923 is_latin_shortcut_key(quint32 aKeyval) |
|
1924 { |
|
1925 return ((Qt::Key_0 <= aKeyval && aKeyval <= Qt::Key_9) || |
|
1926 (Qt::Key_A <= aKeyval && aKeyval <= Qt::Key_Z)); |
|
1927 } |
|
1928 |
|
1929 nsEventStatus |
|
1930 nsWindow::DispatchCommandEvent(nsIAtom* aCommand) |
|
1931 { |
|
1932 WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this); |
|
1933 |
|
1934 nsEventStatus status; |
|
1935 DispatchEvent(&event, status); |
|
1936 |
|
1937 return status; |
|
1938 } |
|
1939 |
|
1940 nsEventStatus |
|
1941 nsWindow::DispatchContentCommandEvent(int32_t aMsg) |
|
1942 { |
|
1943 WidgetContentCommandEvent event(true, aMsg, this); |
|
1944 |
|
1945 nsEventStatus status; |
|
1946 DispatchEvent(&event, status); |
|
1947 |
|
1948 return status; |
|
1949 } |
|
1950 |
|
1951 |
|
1952 static void |
|
1953 GetBrandName(nsXPIDLString& brandName) |
|
1954 { |
|
1955 nsCOMPtr<nsIStringBundleService> bundleService = |
|
1956 mozilla::services::GetStringBundleService(); |
|
1957 |
|
1958 nsCOMPtr<nsIStringBundle> bundle; |
|
1959 if (bundleService) { |
|
1960 bundleService->CreateBundle( |
|
1961 "chrome://branding/locale/brand.properties", |
|
1962 getter_AddRefs(bundle)); |
|
1963 } |
|
1964 |
|
1965 if (bundle) { |
|
1966 bundle->GetStringFromName( |
|
1967 MOZ_UTF16("brandShortName"), |
|
1968 getter_Copies(brandName)); |
|
1969 } |
|
1970 |
|
1971 if (brandName.IsEmpty()) { |
|
1972 brandName.Assign(NS_LITERAL_STRING("Mozilla")); |
|
1973 } |
|
1974 } |
|
1975 |
|
1976 NS_IMETHODIMP |
|
1977 nsWindow::SetWindowClass(const nsAString &xulWinType) |
|
1978 { |
|
1979 if (!mWidget) { |
|
1980 return NS_ERROR_FAILURE; |
|
1981 } |
|
1982 |
|
1983 nsXPIDLString brandName; |
|
1984 GetBrandName(brandName); |
|
1985 |
|
1986 #ifdef MOZ_X11 |
|
1987 XClassHint *class_hint = XAllocClassHint(); |
|
1988 if (!class_hint) { |
|
1989 return NS_ERROR_OUT_OF_MEMORY; |
|
1990 } |
|
1991 const char *role = nullptr; |
|
1992 class_hint->res_name = ToNewCString(xulWinType); |
|
1993 if (!class_hint->res_name) { |
|
1994 XFree(class_hint); |
|
1995 return NS_ERROR_OUT_OF_MEMORY; |
|
1996 } |
|
1997 class_hint->res_class = ToNewCString(brandName); |
|
1998 if (!class_hint->res_class) { |
|
1999 nsMemory::Free(class_hint->res_name); |
|
2000 XFree(class_hint); |
|
2001 return NS_ERROR_OUT_OF_MEMORY; |
|
2002 } |
|
2003 |
|
2004 // Parse res_name into a name and role. Characters other than |
|
2005 // [A-Za-z0-9_-] are converted to '_'. Anything after the first |
|
2006 // colon is assigned to role; if there's no colon, assign the |
|
2007 // whole thing to both role and res_name. |
|
2008 for (char *c = class_hint->res_name; *c; c++) { |
|
2009 if (':' == *c) { |
|
2010 *c = 0; |
|
2011 role = c + 1; |
|
2012 } |
|
2013 else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c))) |
|
2014 *c = '_'; |
|
2015 } |
|
2016 class_hint->res_name[0] = toupper(class_hint->res_name[0]); |
|
2017 if (!role) role = class_hint->res_name; |
|
2018 |
|
2019 QWindow *widget = mWidget; |
|
2020 // If widget not show, handle might be null |
|
2021 if (widget && widget->winId()) { |
|
2022 XSetClassHint(gfxQtPlatform::GetXDisplay(widget), |
|
2023 widget->winId(), |
|
2024 class_hint); |
|
2025 } |
|
2026 |
|
2027 nsMemory::Free(class_hint->res_class); |
|
2028 nsMemory::Free(class_hint->res_name); |
|
2029 XFree(class_hint); |
|
2030 #endif |
|
2031 |
|
2032 return NS_OK; |
|
2033 } |
|
2034 |
|
2035 void |
|
2036 nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool aRepaint) |
|
2037 { |
|
2038 LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this, |
|
2039 aWidth, aHeight)); |
|
2040 |
|
2041 mNeedsResize = false; |
|
2042 |
|
2043 mWidget->resize(aWidth, aHeight); |
|
2044 |
|
2045 if (aRepaint) { |
|
2046 mWidget->renderLater(); |
|
2047 } |
|
2048 } |
|
2049 |
|
2050 void |
|
2051 nsWindow::NativeResize(int32_t aX, int32_t aY, |
|
2052 int32_t aWidth, int32_t aHeight, |
|
2053 bool aRepaint) |
|
2054 { |
|
2055 LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this, |
|
2056 aX, aY, aWidth, aHeight)); |
|
2057 |
|
2058 mNeedsResize = false; |
|
2059 mNeedsMove = false; |
|
2060 |
|
2061 mWidget->setGeometry(aX, aY, aWidth, aHeight); |
|
2062 |
|
2063 if (aRepaint) { |
|
2064 mWidget->renderLater(); |
|
2065 } |
|
2066 } |
|
2067 |
|
2068 void |
|
2069 nsWindow::NativeShow(bool aAction) |
|
2070 { |
|
2071 if (aAction) { |
|
2072 // On e10s, we never want the child process or plugin process |
|
2073 // to go fullscreen because if we do the window because visible |
|
2074 // do to disabled Qt-Xembed |
|
2075 mWidget->show(); |
|
2076 // unset our flag now that our window has been shown |
|
2077 mNeedsShow = false; |
|
2078 } |
|
2079 else { |
|
2080 mWidget->hide(); |
|
2081 } |
|
2082 } |
|
2083 |
|
2084 NS_IMETHODIMP |
|
2085 nsWindow::SetHasTransparentBackground(bool aTransparent) |
|
2086 { |
|
2087 return NS_ERROR_NOT_IMPLEMENTED; |
|
2088 } |
|
2089 |
|
2090 NS_IMETHODIMP |
|
2091 nsWindow::GetHasTransparentBackground(bool& aTransparent) |
|
2092 { |
|
2093 aTransparent = mIsTransparent; |
|
2094 return NS_OK; |
|
2095 } |
|
2096 |
|
2097 void * |
|
2098 nsWindow::SetupPluginPort(void) |
|
2099 { |
|
2100 NS_WARNING("Not implemented"); |
|
2101 return nullptr; |
|
2102 } |
|
2103 |
|
2104 nsresult |
|
2105 nsWindow::SetWindowIconList(const nsTArray<nsCString> &aIconList) |
|
2106 { |
|
2107 QIcon icon; |
|
2108 |
|
2109 for (uint32_t i = 0; i < aIconList.Length(); ++i) { |
|
2110 const char *path = aIconList[i].get(); |
|
2111 LOG(("window [%p] Loading icon from %s\n", (void *)this, path)); |
|
2112 icon.addFile(path); |
|
2113 } |
|
2114 |
|
2115 mWidget->setIcon(icon); |
|
2116 |
|
2117 return NS_OK; |
|
2118 } |
|
2119 |
|
2120 void |
|
2121 nsWindow::SetDefaultIcon(void) |
|
2122 { |
|
2123 SetIcon(NS_LITERAL_STRING("default")); |
|
2124 } |
|
2125 |
|
2126 void nsWindow::QWidgetDestroyed() |
|
2127 { |
|
2128 mWidget = nullptr; |
|
2129 } |
|
2130 |
|
2131 |
|
2132 NS_IMETHODIMP |
|
2133 nsWindow::HideWindowChrome(bool aShouldHide) |
|
2134 { |
|
2135 if (!mWidget) { |
|
2136 // Nothing to hide |
|
2137 return NS_ERROR_FAILURE; |
|
2138 } |
|
2139 |
|
2140 // Sawfish, metacity, and presumably other window managers get |
|
2141 // confused if we change the window decorations while the window |
|
2142 // is visible. |
|
2143 bool wasVisible = false; |
|
2144 if (mWidget->isVisible()) { |
|
2145 NativeShow(false); |
|
2146 wasVisible = true; |
|
2147 } |
|
2148 |
|
2149 if (wasVisible) { |
|
2150 NativeShow(true); |
|
2151 } |
|
2152 |
|
2153 return NS_OK; |
|
2154 } |
|
2155 |
|
2156 ////////////////////////////////////////////////////////////////////// |
|
2157 |
|
2158 NS_IMETHODIMP_(bool) |
|
2159 nsWindow::HasGLContext() |
|
2160 { |
|
2161 return false; |
|
2162 } |
|
2163 |
|
2164 |
|
2165 nsIWidget* |
|
2166 nsWindow::GetParent(void) |
|
2167 { |
|
2168 return mParent; |
|
2169 } |
|
2170 |
|
2171 float |
|
2172 nsWindow::GetDPI() |
|
2173 { |
|
2174 return qApp->primaryScreen()->logicalDotsPerInch(); |
|
2175 } |
|
2176 |
|
2177 void |
|
2178 nsWindow::OnDestroy(void) |
|
2179 { |
|
2180 if (mOnDestroyCalled) { |
|
2181 return; |
|
2182 } |
|
2183 |
|
2184 mOnDestroyCalled = true; |
|
2185 |
|
2186 // release references to children and device context |
|
2187 nsBaseWidget::OnDestroy(); |
|
2188 |
|
2189 // let go of our parent |
|
2190 mParent = nullptr; |
|
2191 |
|
2192 nsCOMPtr<nsIWidget> kungFuDeathGrip = this; |
|
2193 NotifyWindowDestroyed(); |
|
2194 } |
|
2195 |
|
2196 bool |
|
2197 nsWindow::AreBoundsSane(void) |
|
2198 { |
|
2199 if (mBounds.width > 0 && mBounds.height > 0) { |
|
2200 return true; |
|
2201 } |
|
2202 |
|
2203 return false; |
|
2204 } |
|
2205 |
|
2206 void |
|
2207 nsWindow::SetSoftwareKeyboardState(bool aOpen, |
|
2208 const InputContextAction& aAction) |
|
2209 { |
|
2210 if (aOpen) { |
|
2211 NS_ENSURE_TRUE_VOID(mInputContext.mIMEState.mEnabled != |
|
2212 IMEState::DISABLED); |
|
2213 |
|
2214 // Ensure that opening the virtual keyboard is allowed for this specific |
|
2215 // InputContext depending on the content.ime.strict.policy pref |
|
2216 if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN && |
|
2217 Preferences::GetBool("content.ime.strict_policy", false) && |
|
2218 !aAction.ContentGotFocusByTrustedCause() && |
|
2219 !aAction.UserMightRequestOpenVKB()) { |
|
2220 return; |
|
2221 } |
|
2222 } |
|
2223 |
|
2224 if (aOpen) { |
|
2225 qApp->inputMethod()->show(); |
|
2226 } else { |
|
2227 qApp->inputMethod()->hide(); |
|
2228 } |
|
2229 |
|
2230 return; |
|
2231 } |
|
2232 |
|
2233 |
|
2234 void |
|
2235 nsWindow::ProcessMotionEvent() |
|
2236 { |
|
2237 if (mMoveEvent.needDispatch) { |
|
2238 WidgetMouseEvent event(true, NS_MOUSE_MOVE, this, |
|
2239 WidgetMouseEvent::eReal); |
|
2240 |
|
2241 event.refPoint.x = nscoord(mMoveEvent.pos.x()); |
|
2242 event.refPoint.y = nscoord(mMoveEvent.pos.y()); |
|
2243 |
|
2244 event.InitBasicModifiers(mMoveEvent.modifiers & Qt::ControlModifier, |
|
2245 mMoveEvent.modifiers & Qt::AltModifier, |
|
2246 mMoveEvent.modifiers & Qt::ShiftModifier, |
|
2247 mMoveEvent.modifiers & Qt::MetaModifier); |
|
2248 event.clickCount = 0; |
|
2249 |
|
2250 DispatchEvent(&event); |
|
2251 mMoveEvent.needDispatch = false; |
|
2252 } |
|
2253 |
|
2254 mTimerStarted = false; |
|
2255 } |
|
2256 |