• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeui
 

tdeui

  • tdeui
qxembed.cpp
1 /****************************************************************************
2  Implementation of QXEmbed class
3 
4  Copyright (C) 1999-2002 Trolltech AS
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 *****************************************************************************/
21 
22 
23 // L-000: About comments marked with Lxxxx.
24 //
25 // These comments represent an attempt to provide a more adequate
26 // documentation to KDE developpers willing to modify QXEmbed. Keep in
27 // mind that these comments were written long after most of the code.
28 // Please improve them if you spot something wrong or missing
29 // (Leon Bottou, 26-10-2003).
30 //
31 // Relevant documents:
32 // - QXEmbed developper documentation
33 // (see comments in qxembed.h)
34 // - Xlib Reference Manual
35 // (sections about focus, reparenting, window management)
36 // - ICCCM Manual
37 // (window management)
38 // - XEMBED specification
39 // (http://www.freedesktop.org/Standards/xembed-spec)
40 // - XPLAIN and XEMBED.
41 // <http://lists.kde.org/?w=2&r=1&s=qxembed+variants&q=t>
42 // - Accumulated community knowledge.
43 // <http://lists.kde.org/?w=2&r=1&s=qxembed&q=t>
44 // <http://lists.kde.org/?l=kde-devel&w=2&r=1&s=qxembed&q=b>
45 // <http://lists.kde.org/?l=kfm-devel&w=2&r=1&s=qxembed&q=b>
46 //
47 
48 
49 #include <tqapplication.h>
50 #include <tqptrlist.h>
51 #include <tqptrdict.h>
52 #include <tqguardedptr.h>
53 #include <tqwhatsthis.h>
54 #include <tqfocusdata.h>
55 
56 // L0001: QXEmbed works only under X windows.
57 #ifdef Q_WS_X11
58 
59 # include <X11/X.h>
60 # include <X11/Xlib.h>
61 # include <X11/Xutil.h>
62 # include <X11/Xatom.h>
63 # define XK_MISCELLANY
64 # define XK_LATIN1
65 # include <X11/keysymdef.h>
66 # include <kdebug.h>
67 # include <kxerrorhandler.h>
68 
69 // L0002: Is file config.h KDE specific?
70 # include <config.h>
71 # ifdef HAVE_UNISTD_H
72 # include <unistd.h>
73 # ifdef HAVE_USLEEP
74 # define USLEEP(x) usleep(x)
75 # else
76 # define USLEEP(x) sleep(0)
77 # endif
78 # else
79 # define USLEEP(x) sleep(0)
80 # endif
81 
82 # include "qxembed.h"
83 
84 // L0003: This keysym is used for focus navigation.
85 # ifndef XK_ISO_Left_Tab
86 # define XK_ISO_Left_Tab 0xFE20
87 # endif
88 
89 // L0004: Conflicts between X11 and Qt definitions.
90 const int XFocusOut = FocusOut;
91 const int XFocusIn = FocusIn;
92 const int XKeyPress = KeyPress;
93 const int XKeyRelease = KeyRelease;
94 # undef KeyRelease
95 # undef KeyPress
96 # undef FocusOut
97 # undef FocusIn
98 
99 // L0005: Variables defined in qapplication_x11.cpp
100 extern Atom tqt_wm_protocols;
101 extern Atom tqt_wm_delete_window;
102 extern Atom tqt_wm_take_focus;
103 extern Atom tqt_wm_state;
104 
105 // L0006: X11 atoms private to QXEmbed
106 static Atom xembed = 0;
107 static Atom context_help = 0;
108 
109 // L0007: Xembed message codes (see XEmbed spec)
110 #define XEMBED_EMBEDDED_NOTIFY 0
111 #define XEMBED_WINDOW_ACTIVATE 1
112 #define XEMBED_WINDOW_DEACTIVATE 2
113 #define XEMBED_REQUEST_FOCUS 3
114 #define XEMBED_FOCUS_IN 4
115 #define XEMBED_FOCUS_OUT 5
116 #define XEMBED_FOCUS_NEXT 6
117 #define XEMBED_FOCUS_PREV 7
118 
119 // L0008: Xembed message details (see XEmbed spec)
120 // -- XEMBED_FOCUS_IN:
121 #define XEMBED_FOCUS_CURRENT 0
122 #define XEMBED_FOCUS_FIRST 1
123 #define XEMBED_FOCUS_LAST 2
124 
125 
126 // L0100: Private data held by the QXEmbed object.
127 // This belongs to the embedder side.
128 class QXEmbedData
129 {
130 public:
131  QXEmbedData(){
132  autoDelete = true;
133  xplain = false;
134  xgrab = false;
135  mapAfterRelease = false;
136  lastPos = TQPoint(0,0);
137  }
138  ~QXEmbedData(){}
139 
140  bool autoDelete; // L0101: See L2600
141  bool xplain; // L0102: See L1100
142  bool xgrab; // L0103: See L2800
143  bool mapAfterRelease;
144  TQWidget* focusProxy; // L0104: See XEmbed spec
145  TQPoint lastPos; // L0105: See L1390
146 };
147 
148 namespace
149 {
150  // L0200: This application wide event filter handles focus
151  // issues in the embedded client.
152  class QXEmbedAppFilter : public TQObject
153  {
154  public:
155  QXEmbedAppFilter() { tqApp->installEventFilter( this ); }
156  ~QXEmbedAppFilter() { }
157  bool eventFilter( TQObject *, TQEvent * );
158  };
159 }
160 
161 // L0201: See L0200, L0740
162 static QXEmbedAppFilter* filter = 0;
163 // L0202: See L0610, L0730
164 static TQPtrDict<TQGuardedPtr<TQWidget> > *focusMap = 0;
165 // L0203: See L0660, L1400, L1450
166 static XKeyEvent last_key_event;
167 
168 // L0300: This class gives access protected members of class TQWidget.
169 // Function focusData() is useful to reimplement tab focus management
170 // (L0620) Function topData() returns a structure QTLWExtra containing
171 // information unique to toplevel windows. This structure contains two
172 // members for the sole use of QXEmbed. Flag `embedded' indicates whether
173 // the toplevel window is embedded using the XEMBED protocol (L0680).
174 // Handle `parentWinId' then records the id of the embedding window.
175 
176 class QPublicWidget : public TQWidget
177 {
178 public:
179  TQTLWExtra* topData() { return TQWidget::topData(); }
180  TQFocusData *focusData(){ return TQWidget::focusData(); }
181  bool focusNextPrev(bool b) { return focusNextPrevChild(b); }
182 };
183 
184 // L0400: This sets a very low level filter for X11 messages.
185 // See qapplication_x11.cpp
186 typedef int (*QX11EventFilter) (XEvent*);
187 extern QX11EventFilter tqt_set_x11_event_filter (QX11EventFilter filter);
188 static QX11EventFilter oldFilter = 0;
189 
190 
191 // L0500: Helper to send XEmbed messages.
192 static void sendXEmbedMessage( WId window, long message, long detail = 0,
193  long data1 = 0, long data2 = 0)
194 {
195  if (!window) return;
196  XEvent ev;
197  memset(&ev, 0, sizeof(ev));
198  ev.xclient.type = ClientMessage;
199  ev.xclient.window = window;
200  ev.xclient.message_type = xembed;
201  ev.xclient.format = 32;
202  ev.xclient.data.l[0] = GET_QT_X_TIME();
203  ev.xclient.data.l[1] = message;
204  ev.xclient.data.l[2] = detail;
205  ev.xclient.data.l[3] = data1;
206  ev.xclient.data.l[4] = data2;
207  XSendEvent(tqt_xdisplay(), window, false, NoEventMask, &ev);
208 }
209 
210 // L0501: Helper to send ICCCM Client messages.
211 // See X11 ICCCM Specification.
212 static void sendClientMessage(Window window, Atom a, long x)
213 {
214  if (!window) return;
215  XEvent ev;
216  memset(&ev, 0, sizeof(ev));
217  ev.xclient.type = ClientMessage;
218  ev.xclient.window = window;
219  ev.xclient.message_type = a;
220  ev.xclient.format = 32;
221  ev.xclient.data.l[0] = x;
222  ev.xclient.data.l[1] = GET_QT_X_TIME();
223  XSendEvent(tqt_xdisplay(), window, false, NoEventMask, &ev);
224 }
225 
226 // L0502: Helper to send fake X11 focus messages.
227 // See X11 Reference Manual and Window Management stuff.
228 static void sendFocusMessage(Window window, int type, int mode, int detail)
229 {
230  if (!window) return;
231  XEvent ev;
232  memset(&ev, 0, sizeof(ev));
233  ev.xfocus.type = type;
234  ev.xfocus.window = window;
235  ev.xfocus.mode = mode;
236  ev.xfocus.detail = detail;
237  XSendEvent(tqt_xdisplay(), window, false, FocusChangeMask, &ev);
238 }
239 
240 
241 // ------------------------------------------------------------
242 // L0600: MOST OF WHAT FOLLOWS CONCERNS THE CLIENT SIDE.
243 // The following code mostly executes inside a Qt application swallowed
244 // by QXEmbed widget. It mostly consists of event filters that fight
245 // the normal Qt mechanisms in order to implement the XEMBED protocol.
246 // All this would be a lot simpler if it was implemented by Qt itself.
247 
248 
249 
250 // L0610: This event filter receives all Qt events. Its main purpose is to
251 // capture the Qt focus events in the embedded client in order to
252 // implement the XEMBED protocol.
253 //
254 // Let's start with a few reminders:
255 //
256 // - X11 only has the concept of the "X11 focus window". This window
257 // basically receives all key events. The ICCCM conventions define
258 // how the window manager and the applications must cooperate to
259 // choose the X11 focus window.
260 //
261 // - Most toolkits, including Qt, maintain the concepts of 'active
262 // widget' and 'Qt focus widget'. A toplevel widget is active when
263 // the X11 focus is set to one of its children. By extension a
264 // widget is active when its toplevel widget is active. There is one
265 // Qt focus widget for each toplevel widget. When the toplevel
266 // widget is active, all key events are sent to the Qt focus widget,
267 // regardless of which descendant of the toplevel window has the X11
268 // focus. Widgets can adjust their appearance according to both
269 // their activation and focus states. The Qt FocusIn and FocusOut
270 // events indicate when a widget simultaneously is active and has
271 // the Qt focus.
272 //
273 // The XEMBED protocol defines ways to communicate abouth both
274 // activation and focus. The embedded client is active as soon as the
275 // embedding window is active (L0676, L0677). A widget in the embedded
276 // client receives key events when (1) it has the Qt focus in the
277 // embedded application, and (2) the QXEmbed widget in the embedding
278 // application is active and has the Qt focus. The Qt library in the
279 // embedded application is unaware of the focus status of the QXEmbed
280 // widget. We must make sure it does the right thing regarding the
281 // sending of focus events and the visual appearance of the focussed
282 // widgets. When the QXEmbed widget looses the Qt focus, we clear the
283 // focus in the embedded client (L1570, L0688). Conversely, when
284 // the QXEmbed widget gains the Qt focus, we restore the Qt focus
285 // window in the embedded client (L1530, L0680, L0683).
286 // Variable focusMap is used to remember which was the Qt focus
287 // widget in the embedded application. All this would be a lot
288 // simpler if it was implemented inside Qt...
289 //
290 // The XPLAIN protocol is much less refined in this respect.
291 // The activation status of the embedded client simply reflect
292 // the focus status of the QXEmbed widget. This is achieved
293 // by sending fake X11 focus message to the client (L1521, L1561).
294 // A passive button grab (L2800) intercepts mouse activity in the
295 // embedded client and sets the Qt focus to the QXEmbed widget
296 // when this happens (L2060). This can be achieved without
297 // cooperation from the client.
298 
299 bool QXEmbedAppFilter::eventFilter( TQObject *o, TQEvent * e)
300 {
301  static bool obeyFocus = false;
302  switch ( e->type() ) {
303  case TQEvent::MouseButtonPress:
304  // L0612: This will become clear with L0614
305  if ( !((TQWidget*)o)->isActiveWindow() )
306  obeyFocus = true;
307  break;
308  case TQEvent::FocusIn:
309  // L0613: FocusIn events either occur because the widget already was
310  // active and has just been given the Qt focus (L0614) or
311  // because the widget already had the Qt focus and just became
312  // active (L0615).
313  if ( TQT_BASE_OBJECT(tqApp->focusWidget()) == TQT_BASE_OBJECT(o) &&
314  ((QPublicWidget*)tqApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
315  TQFocusEvent* fe = (TQFocusEvent*) e;
316  if ( obeyFocus || fe->reason() != TQFocusEvent::ActiveWindow /*|| fe->reason() == TQFocusEvent::Mouse ||
317  fe->reason() == TQFocusEvent::Shortcut*/ ) {
318  // L0614: A widget in the embedded client was just given the Qt focus.
319  // Variable `obeyFocus' suggests that this is the result of mouse
320  // activity in the client. The XEMBED_REQUEST_FOCUS message causes
321  // the embedding widget to take the Qt focus (L2085).
322 #ifdef USE_QT4
323  WId window = ((QPublicWidget*)tqApp->focusWidget()->topLevelWidget())->effectiveWinId();
324 #else // USE_QT4
325  WId window = ((QPublicWidget*)tqApp->focusWidget()->topLevelWidget())->topData()->parentWinId;
326 #endif // USE_QT4
327  focusMap->remove( tqApp->focusWidget()->topLevelWidget() );
328  sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
329  } else if ( fe->reason() == TQFocusEvent::ActiveWindow ) {
330  // L0615: Both the embedder and the embedded client became active.
331  // But we do not know whether the QXEmbed widget has the Qt focus.
332  // So we clear the Qt focus for now. If indeed the QXEmbed widget
333  // has the focus, it will receive a FocusIn message (L1530) and
334  // tell us to restore the focus (L0680, L0683).
335  focusMap->remove( tqApp->focusWidget()->topLevelWidget() );
336  focusMap->insert( tqApp->focusWidget()->topLevelWidget(),
337  new TQGuardedPtr<TQWidget>(tqApp->focusWidget()->topLevelWidget()->focusWidget() ) );
338  // L0616: tqApp->focusWidget() might belong to a modal dialog and not be
339  // equal to tqApp->focusWidget()->topLevelWidget()->focusWidget() !
340  tqApp->focusWidget()->clearFocus();
341  // L0617: ??? [why not {obeyFocus=false; return true;} here?]
342  }
343  obeyFocus = false;
344  }
345  break;
346  case TQEvent::KeyPress:
347  if (TQT_BASE_OBJECT(tqApp->focusWidget()) == TQT_BASE_OBJECT(o) &&
348  ((QPublicWidget*)tqApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
349  // L0620: The following code replaces the Qt code that
350  // handles focus focus changes with the tab key. See the
351  // XEMBED specification for details. The keypress event
352  // arrives here after an interesting itinerary. It is first
353  // saved in the embedding application (L0660). After being
354  // rejected for tab navigation in the embedding application
355  // (L1901), it gets forwarded to the embedded client
356  // (L1400) and arrives here. Depending on the status of
357  // the tab chain in the embedded client, focus navigation
358  // messages are sent back to the embedding application
359  // (L0653, L0654) which then performs tab navigation
360  // (L2081).
361  TQKeyEvent *k = (TQKeyEvent *)e;
362  TQWidget *w = tqApp->focusWidget();
363  // L0621: The following tests are copied from TQWidget::event().
364  bool res = false;
365  bool tabForward = true;
366  if ( !(k->state() & ControlButton || k->state() & AltButton) ) {
367  if ( k->key() == Key_Backtab || (k->key() == Key_Tab && (k->state() & ShiftButton)) ) {
368 #ifdef USE_QT4
369  res = ((QPublicWidget*)w)->focusNextPrev( tabForward = false );
370 #else // USE_QT4
371  TQFocusEvent::setReason( TQFocusEvent::Backtab );
372  res = ((QPublicWidget*)w)->focusNextPrev( tabForward = false );
373  TQFocusEvent::resetReason();
374 #endif // USE_QT4
375  } else if ( k->key() == Key_Tab ) {
376 #ifdef USE_QT4
377  res = ((QPublicWidget*)w)->focusNextPrev( tabForward = true );
378 #else // USE_QT4
379  TQFocusEvent::setReason( TQFocusEvent::Tab );
380  res = ((QPublicWidget*)w)->focusNextPrev( tabForward = true );
381  TQFocusEvent::resetReason();
382 #endif // USE_QT4
383  }
384  }
385  if (res) {
386  // L0625: We changed the focus because of tab/backtab key
387  // Now check whether we have been looping around.
388  TQFocusData *fd = ((QPublicWidget*)w)->focusData();
389 #ifdef USE_QT4
390  WId window = ((QPublicWidget*)w->topLevelWidget())->effectiveWinId();
391 #else // USE_QT4
392  WId window = ((QPublicWidget*)w->topLevelWidget())->topData()->parentWinId;
393 #endif // USE_QT4
394  TQWidget *cw = 0;
395  TQWidget *fw = fd->home();
396  if (tabForward && window) {
397  while (cw != w && cw != fw && cw != w->topLevelWidget())
398  cw = fd->prev();
399  if (cw != w)
400  sendXEmbedMessage( window, XEMBED_FOCUS_NEXT );
401  } else if (window) {
402  while (cw != w && cw != fw && cw != w->topLevelWidget())
403  cw = fd->next();
404  if (cw != w)
405  sendXEmbedMessage( window, XEMBED_FOCUS_PREV );
406  }
407  // L0628: Qt should no longer process this event.
408  return true;
409  }
410  }
411  break;
412  default:
413  break;
414  }
415  // L0640: Application gets to see the events anyway.
416  return false;
417 }
418 
419 // L0650: This filter receives all XEvents in both the client and the embedder.
420 // Most of it involves the embedded client (except L0660, L0671).
421 static int qxembed_x11_event_filter( XEvent* e)
422 {
423  switch ( e->type ) {
424  case XKeyPress:
425  case XKeyRelease: {
426  // L0660: This is for the embedding side (L1450).
427  last_key_event = e->xkey;
428  break;
429  }
430  case ClientMessage:
431  if ( e->xclient.message_type == xembed ) {
432  // L0670: This is where the XEmbed messages are
433  // processed on the client side.
434  Time msgtime = (Time) e->xclient.data.l[0];
435  long message = e->xclient.data.l[1];
436  long detail = e->xclient.data.l[2];
437  // L0671: Keep Qt message time up to date
438  if ( msgtime > GET_QT_X_TIME() )
439  SET_QT_X_TIME(msgtime);
440  TQWidget* w = TQT_TQWIDGET(TQWidget::find( e->xclient.window ));
441  if ( !w )
442  break;
443  switch ( message) {
444  case XEMBED_EMBEDDED_NOTIFY: {
445  // L0675: We just have been embedded into a XEMBED aware widget.
446  TQTLWExtra *extra = ((QPublicWidget*)w->topLevelWidget())->topData();
447  extra->embedded = 1;
448 #ifdef USE_QT4
449  // [FIXME]
450  printf("[FIXME] WId not set in tdelibs/tdeui/qxembed.cpp\n");
451 #else // USE_QT4
452  extra->parentWinId = e->xclient.data.l[3];
453 #endif // USE_QT4
454  w->topLevelWidget()->show();
455  break;
456  }
457  case XEMBED_WINDOW_ACTIVATE: {
458  // L0676: Embedding window becomes active. Send a fake XFocusIn
459  // to convince Qt that we are active as well. Qt will send
460  // us a focus notification (L0615) that we will intercept to
461  // ensure that we have no Qt focus widget yet. The Qt focus
462  // widget might later be set in L0680.
463  XEvent ev;
464  memset(&ev, 0, sizeof(ev));
465  ev.xfocus.display = tqt_xdisplay();
466  ev.xfocus.type = XFocusIn;
467  ev.xfocus.window = w->topLevelWidget()->winId();
468  ev.xfocus.mode = NotifyNormal;
469  ev.xfocus.detail = NotifyAncestor;
470  tqApp->x11ProcessEvent( &ev );
471  }
472  break;
473  case XEMBED_WINDOW_DEACTIVATE: {
474  // L0677: Embedding window becomes inactive. Send a fake XFocusOut
475  // event to convince Qt that we no longer are active. We will
476  // receive extra Qt FocusOut events but we do not care.
477  XEvent ev;
478  memset(&ev, 0, sizeof(ev));
479  ev.xfocus.display = tqt_xdisplay();
480  ev.xfocus.type = XFocusOut;
481  ev.xfocus.window = w->topLevelWidget()->winId();
482  ev.xfocus.mode = NotifyNormal;
483  ev.xfocus.detail = NotifyAncestor;
484  tqApp->x11ProcessEvent( &ev );
485  }
486  break;
487  case XEMBED_FOCUS_IN:
488  // L0680: Embedding application gives us the focus.
489  {
490  // L0681: Search saved focus widget.
491  TQWidget* focusCurrent = 0;
492  TQGuardedPtr<TQWidget>* fw = focusMap->find( w->topLevelWidget() );
493  if ( fw ) {
494  focusCurrent = *fw;
495  // L0682: Remove it from the map
496  focusMap->remove( w->topLevelWidget() );
497  }
498  switch ( detail ) {
499  case XEMBED_FOCUS_CURRENT:
500  // L0683: Set focus on saved focus widget
501  if ( focusCurrent ) {
502  focusCurrent->setFocus();
503  if( QXEmbed* emb = tqt_dynamic_cast< QXEmbed* >( focusCurrent ))
504  emb->updateEmbeddedFocus( true );
505  }
506  else if ( !w->topLevelWidget()->focusWidget() )
507  w->topLevelWidget()->setFocus();
508  break;
509  case XEMBED_FOCUS_FIRST:
510  {
511  // L0684: Search first widget in tab chain
512 #ifdef USE_QT4
513  w->topLevelWidget()->setFocus();
514  ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(true);
515 #else // USE_QT4
516  TQFocusEvent::setReason( TQFocusEvent::Tab );
517  w->topLevelWidget()->setFocus();
518  ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(true);
519  TQFocusEvent::resetReason();
520 #endif // USE_QT4
521  }
522  break;
523  case XEMBED_FOCUS_LAST:
524  {
525  // L0686: Search last widget in tab chain
526 #ifdef USE_QT4
527  w->topLevelWidget()->setFocus();
528  ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(false);
529 #else // USE_QT4
530  TQFocusEvent::setReason( TQFocusEvent::Backtab );
531  w->topLevelWidget()->setFocus();
532  ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(false);
533  TQFocusEvent::resetReason();
534 #endif // USE_QT4
535  }
536  break;
537  default:
538  break;
539  }
540  }
541  break;
542  case XEMBED_FOCUS_OUT:
543  // L0688: Embedding application takes the focus away
544  // We first record what the focus widget was
545  // and clear the Qt focus.
546  if ( w->topLevelWidget()->focusWidget() ) {
547  if( QXEmbed* emb = tqt_dynamic_cast< QXEmbed* >( w->topLevelWidget()->focusWidget()))
548  emb->updateEmbeddedFocus( false );
549  focusMap->insert( w->topLevelWidget(),
550  new TQGuardedPtr<TQWidget>(w->topLevelWidget()->focusWidget() ) );
551  w->topLevelWidget()->focusWidget()->clearFocus();
552  }
553  break;
554  default:
555  break;
556  }
557  } else if ( e->xclient.format == 32 && e->xclient.message_type ) {
558  if ( e->xclient.message_type == tqt_wm_protocols ) {
559  TQWidget* w = TQT_TQWIDGET(TQWidget::find( e->xclient.window ));
560  if ( !w )
561  break;
562  // L0690: This is for the embedding side!
563  // See L0902 for more information about the focus proxy.
564  // Window manager may send WM_TAKE_FOCUS messages to the
565  // embedding application to indicate that it becomes active.
566  // But this also suggests that the window manager has
567  // changed the X11 focus. We want to make sure it goes
568  // to the focus proxy window eventually.
569  Atom a = e->xclient.data.l[0];
570  if ( a == tqt_wm_take_focus ) {
571  // L0695: update Qt message time variable
572  if ( (ulong) e->xclient.data.l[1] > GET_QT_X_TIME() )
573  SET_QT_X_TIME(e->xclient.data.l[1]);
574  // L0696: There is no problem when the window is not active.
575  // Qt will generate a WindowActivate event that will
576  // do the job (L1310). This does not happen if the
577  // window is already active. So we simulate it.
578  if ( w->isActiveWindow() ) {
579  TQEvent e( TQEvent::WindowActivate );
580  TQApplication::sendEvent( w, &e );
581  }
582  }
583  }
584  }
585  break;
586  default:
587  break;
588  }
589  // L0698: The next x11 filter
590  if ( oldFilter )
591  return oldFilter( e );
592  // L0699: Otherwise process the event as usual.
593  return false;
594 }
595 
596 
597 
598 // L0700: Install the xembed filters in both client and embedder sides.
599 // This function is called automatically when using
600 // embedClientIntoWindow() or creating an instance of QXEmbed You may
601 // have to call it manually for a client when using embedder-side
602 // embedding, though.
603 void QXEmbed::initialize()
604 {
605  static bool is_initialized = false;
606  if ( is_initialized )
607  return;
608 
609  // L0710: Atom used by the XEMBED protocol.
610  xembed = XInternAtom( tqt_xdisplay(), "_XEMBED", false );
611  // L0720: Install low level filter for X11 events (L0650)
612  oldFilter = tqt_set_x11_event_filter( qxembed_x11_event_filter );
613  // L0730: See L0610 for an explanation about focusMap.
614  focusMap = new TQPtrDict<TQGuardedPtr<TQWidget> >;
615  focusMap->setAutoDelete( true );
616  // L0740: Create client side application wide event filter (L0610)
617  filter = new QXEmbedAppFilter;
618 
619  is_initialized = true;
620 }
621 
622 
623 
624 
625 
626 // ------------------------------------------------------------
627 // L0800: MOST OF WHAT FOLLOWS CONCERNS THE EMBEDDER SIDE.
628 // Things that happen inside a Qt application that contain
629 // a QXEmbed widget for embedding other applications.
630 // This applies to both the XEMBED and XPLAIN protocols.
631 // Deviations are commented below.
632 
633 
634 
635 // L0810: Class QXEmbed.
636 // A QXEmbed widget serves as an embedder that can manage one single
637 // embedded X-window. These so-called client windows can be arbitrary
638 // Qt or non Qt applications. There are two different ways of using
639 // QXEmbed, from the client side or from the embedder's side.
640 
641 
642 // L0900: Constructs a xembed widget.
643 QXEmbed::QXEmbed(TQWidget *parent, const char *name, WFlags f)
644  : TQWidget(parent, name, f)
645 {
646  // L0901: Create private data. See L0100.
647  d = new QXEmbedData;
648  // L0902: Create focus proxy widget. See XEmbed specification.
649  // Each QXEmbed widget has a focus proxy window. Every single
650  // QXEmbed widget tries to force its focus proxy window onto the
651  // whole embedding application. They compete between themselves and
652  // against Qt (L0690, L0914, L1040, L1310, L1510, L1580).
653  // This would be much simpler if implemented within Qt.
654  d->focusProxy = new TQWidget( topLevelWidget(), "xembed_focus" );
655  d->focusProxy->setGeometry( -1, -1, 1, 1 );
656  d->focusProxy->show();
657  // make sure it's shown - for XSetInputFocus
658  TQApplication::sendPostedEvents( d->focusProxy, 0 );
659  // L0903: Install the client side event filters
660  // because they also provide services for the embedder side
661  // See L0660, L0671, L0685.
662  initialize();
663  window = 0;
664  setFocusPolicy(TQ_StrongFocus);
665  setKeyCompression( false );
666 
667  // L0910: Trick Qt to create extraData();
668  (void) topData();
669 
670  // L0912: We are mostly interested in SubstructureNotify
671  // This is sent when something happens to the children of
672  // the X11 window associated with the QXEmbed widget.
673  XSelectInput(tqt_xdisplay(), winId(),
674  KeyPressMask | KeyReleaseMask |
675  ButtonPressMask | ButtonReleaseMask |
676  KeymapStateMask |
677  ButtonMotionMask |
678  PointerMotionMask | // may need this, too
679  EnterWindowMask | LeaveWindowMask |
680  FocusChangeMask |
681  ExposureMask |
682  StructureNotifyMask |
683  SubstructureRedirectMask |
684  SubstructureNotifyMask
685  );
686  // L0913: all application events pass through eventFilter().
687  // This is mostly used to force the X11 focus on the
688  // proxy focus window. See L1300.
689  topLevelWidget()->installEventFilter( this );
690  tqApp->installEventFilter( this );
691 
692  // L0914: Start moving the X11 focus on the focus proxy window.
693  // See L1581 to know why we do not use isActiveWindow().
694  if ( tqApp->activeWindow() == topLevelWidget() )
695  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
696  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
697  RevertToParent, GET_QT_X_TIME() );
698  // L0915: ??? [drag&drop?]
699  setAcceptDrops( true );
700 }
701 
702 // L1000: Destructor must dispose of the embedded client window.
703 QXEmbed::~QXEmbed()
704 {
705  // L1010: Make sure no pointer grab is left.
706  if ( d && d->xgrab)
707  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, winId() );
708  if ( window && ( autoDelete() || !d->xplain ))
709  {
710  // L1021: Hide the window and safely reparent it into the root,
711  // otherwise it would be destroyed by X11 together
712  // with this QXEmbed's window.
713 #if 0
714 // TODO: The proper XEmbed way would be to unmap the window, and the embedded
715 // app would detect the embedding has ended, and do whatever it finds appropriate.
716 // However, QXEmbed currently doesn't provide support for this detection,
717 // so for the time being, it's better to leave the window mapped as toplevel window.
718 // This will be ever more complicated with the systray windows, as the simple API
719 // for them (KWin::setSystemTrayWindowFor()) doesn't make it possible to detect
720 // themselves they have been released from systray, but KWin requires them
721 // to be visible to allow next Kicker instance to swallow them.
722 // See also below the L1022 comment.
723 // XUnmapWindow( tqt_xdisplay(), window );
724 #else
725  if( autoDelete())
726  XUnmapWindow( tqt_xdisplay(), window );
727 #endif
728  XReparentWindow(tqt_xdisplay(), window, tqt_xrootwin(), 0, 0);
729  if( !d->xplain )
730  XRemoveFromSaveSet( tqt_xdisplay(), window );
731  if( d->mapAfterRelease )
732  XMapWindow( tqt_xdisplay(), window );
733  XSync(tqt_xdisplay(), false);
734  // L1022: Send the WM_DELETE_WINDOW message
735  if( autoDelete() /*&& d->xplain*/ )
736  // This sendDelete should only apply to XPLAIN.
737  // XEMBED apps are supposed to detect when the embedding ends.
738  // ??? [We do not do this detection yet!
739  // So we sendDelete() instead.]
740  sendDelete();
741  }
742  window = 0;
743  // L01040: Our focus proxy window will be destroyed as well.
744  // Make sure that the X11 focus is not lost in the process.
745  Window focus;
746  int revert;
747  XGetInputFocus( tqt_xdisplay(), &focus, &revert );
748  if( focus == d->focusProxy->winId())
749  XSetInputFocus( tqt_xdisplay(), topLevelWidget()->winId(), RevertToParent, GET_QT_X_TIME() );
750  // L01045: Delete our private data.
751  delete d;
752 }
753 
754 
755 // L1050: Sends a WM_DELETE_WINDOW message to the embedded window. This is
756 // what typically happens when you click on the close button of a
757 // window manager decoration.
758 void QXEmbed::sendDelete( void )
759 {
760  if (window)
761  {
762  sendClientMessage(window, tqt_wm_protocols, tqt_wm_delete_window);
763  XFlush( tqt_xdisplay() );
764  }
765 }
766 
767 // L1100: Sets the protocol used for embedding windows.
768 // This function must be called before embedding a window.
769 // Protocol XEMBED provides maximal functionality (focus, tabs, etc)
770 // but requires explicit cooperation from the embedded window.
771 // Protocol XPLAIN provides maximal compatibility with
772 // embedded applications that do not support the XEMBED protocol.
773 // The default is XEMBED.
774 void QXEmbed::setProtocol( Protocol proto )
775 {
776  if (!window) {
777  d->xplain = false;
778  if (proto == XPLAIN)
779  d->xplain = true;
780  }
781 }
782 
783 // L1150: Returns the protocol used for embedding the current window.
784 QXEmbed::Protocol QXEmbed::protocol()
785 {
786  if (d->xplain)
787  return XPLAIN;
788  return XEMBED;
789 }
790 
791 
792 // L1200: QXEmbed widget size changes: resize embedded window.
793 void QXEmbed::resizeEvent(TQResizeEvent*)
794 {
795  if (window)
796  XResizeWindow(tqt_xdisplay(), window, width(), height());
797 }
798 
799 // L1250: QXEmbed widget is shown: make sure embedded window is visible.
800 void QXEmbed::showEvent(TQShowEvent*)
801 {
802  if (window)
803  XMapRaised(tqt_xdisplay(), window);
804 }
805 
806 
807 // L1300: This event filter sees all application events (L0913).
808 bool QXEmbed::eventFilter( TQObject *o, TQEvent * e)
809 {
810 
811  switch ( e->type() ) {
812  case TQEvent::WindowActivate:
813  if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(topLevelWidget()) ) {
814  // L1310: Qt thinks the application window has just been activated.
815  // Make sure the X11 focus is on the focus proxy window. See L0686.
816  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
817  if (! hasFocus() )
818  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
819  RevertToParent, GET_QT_X_TIME() );
820  if (d->xplain)
821  // L1311: Activation has changed. Grab state might change. See L2800.
822  checkGrab();
823  else
824  // L1312: Let the client know that we just became active
825  sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE );
826  }
827  break;
828  case TQEvent::WindowDeactivate:
829  if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(topLevelWidget()) ) {
830  if (d->xplain)
831  // L1321: Activation has changed. Grab state might change. See L2800.
832  checkGrab();
833  else
834  // L1322: Let the client know that we are no longer active
835  sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE );
836  }
837  break;
838  case TQEvent::Move:
839  {
840  TQWidget* pos = this;
841  while( TQT_BASE_OBJECT(pos) != TQT_BASE_OBJECT(o) && TQT_BASE_OBJECT(pos) != TQT_BASE_OBJECT(topLevelWidget()))
842  pos = pos->parentWidget();
843  if( TQT_BASE_OBJECT(pos) == TQT_BASE_OBJECT(o) ) {
844  // L1390: Send fake configure notify events whenever the
845  // global position of the client changes. See L2900.
846  TQPoint globalPos = mapToGlobal(TQPoint(0,0));
847  if (globalPos != d->lastPos) {
848  d->lastPos = globalPos;
849  sendSyntheticConfigureNotifyEvent();
850  }
851  }
852  }
853  break;
854  default:
855  break;
856  }
857  return false;
858 }
859 
860 // L1350: ??? [why this?]
861 bool QXEmbed::event( TQEvent * e)
862 {
863  return TQWidget::event( e );
864 }
865 
866 // L1400: Forward keypress event to the client
867 // Receiving a Qt key event indicates that
868 // the QXEmbed object has the Qt focus.
869 // The X11 event that caused the Qt key event
870 // must be forwarded to the client.
871 // See L0660.
872 void QXEmbed::keyPressEvent( TQKeyEvent *)
873 {
874  if (!window)
875  return;
876  last_key_event.window = window;
877  XSendEvent(tqt_xdisplay(), window, false, KeyPressMask, (XEvent*)&last_key_event);
878 
879 }
880 
881 // L1450: Forward keyrelease event to the client.
882 // See comment L1400.
883 void QXEmbed::keyReleaseEvent( TQKeyEvent *)
884 {
885  if (!window)
886  return;
887  last_key_event.window = window;
888  XSendEvent(tqt_xdisplay(), window, false, KeyReleaseMask, (XEvent*)&last_key_event);
889 }
890 
891 // L1500: Handle Qt focus in event.
892 void QXEmbed::focusInEvent( TQFocusEvent * e ){
893  if (!window)
894  return;
895  // L1510: This is a good time to set the X11 focus on the focus proxy window.
896  // Except if the the embedding application itself is embedded into another.
897  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
898  if ( tqApp->activeWindow() == topLevelWidget() )
899  // L1511: Alter X focus only when window is active.
900  // This is dual safety here because FocusIn implies this.
901  // But see L1581 for an example where this really matters.
902  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
903  RevertToParent, GET_QT_X_TIME() );
904  if (d->xplain) {
905  // L1520: Qt focus has changed. Grab state might change. See L2800.
906  checkGrab();
907  // L1521: Window managers activate applications by setting the X11 focus.
908  // We cannot do this (see L1510) but we can send a fake focus event
909  // and forward the X11 key events ourselves (see L1400, L1450).
910  sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
911  } else {
912  // L1530: No need for fake events with XEMBED.
913  // Just inform the client. It knows what to do.
914  int detail = XEMBED_FOCUS_CURRENT;
915  // L1531: When the focus change is caused by the tab key,
916  // the client must select the first (or last) widget of
917  // its own tab chain.
918  if ( e->reason() == TQFocusEvent::Tab )
919  detail = XEMBED_FOCUS_FIRST;
920  else if ( e->reason() == TQFocusEvent::Backtab )
921  detail = XEMBED_FOCUS_LAST;
922  sendXEmbedMessage( window, XEMBED_FOCUS_IN, detail);
923  }
924 }
925 
926 // L1550: Handle Qt focus out event.
927 void QXEmbed::focusOutEvent( TQFocusEvent * ){
928  if (!window)
929  return;
930  if (d->xplain) {
931  // L1560: Qt focus has changed. Grab state might change. See L2800.
932  checkGrab();
933  // L1561: Send fake focus out message. See L1521.
934  sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer );
935  } else {
936  // L1570: Send XEMBED focus out message. See L1531.
937  sendXEmbedMessage( window, XEMBED_FOCUS_OUT );
938  }
939  // L1580: The QXEmbed object might loose the focus because its
940  // toplevel window looses the X11 focus and is no longer active,
941  // or simply because the Qt focus has been moved to another widget.
942  // In the latter case only, we want to make sure that the X11 focus
943  // is properly set to the X11 focus widget. We do this because
944  // the client application might have moved the X11 focus after
945  // receiving the fake focus messages.
946  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
947  if ( tqApp->activeWindow() == topLevelWidget() )
948  // L1581: Alter X focus only when window is active.
949  // The test above is not the same as isActiveWindow().
950  // Function isActiveWindow() also returns true when a modal
951  // dialog child of this window is active.
952  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
953  RevertToParent, GET_QT_X_TIME() );
954 }
955 
956 
957 // When QXEmbed has TQt focus and gets/loses X focus, make sure the client knows
958 // about the state of the focus.
959 void QXEmbed::updateEmbeddedFocus( bool hasfocus ){
960  if (!window || d->xplain)
961  return;
962  if( hasfocus )
963  sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
964  else
965  sendXEmbedMessage( window, XEMBED_FOCUS_OUT);
966 }
967 
968 // L1600: Helper for QXEmbed::embed()
969 // Check whether a window is in withdrawn state.
970 static bool wstate_withdrawn( WId winid )
971 {
972  Atom type;
973  int format;
974  unsigned long length, after;
975  unsigned char *data;
976  int r = XGetWindowProperty( tqt_xdisplay(), winid, tqt_wm_state, 0, 2,
977  false, AnyPropertyType, &type, &format,
978  &length, &after, &data );
979  bool withdrawn = true;
980  // L1610: Non managed windows have no WM_STATE property.
981  // Returning true ensures that the loop L1711 stops.
982  if ( r == Success && data && format == 32 ) {
983  TQ_UINT32 *wstate = (TQ_UINT32*)data;
984  withdrawn = (*wstate == WithdrawnState );
985  XFree( (char *)data );
986  }
987  return withdrawn;
988 }
989 
990 // L1650: Helper for QXEmbed::embed()
991 // Get the X11 id of the parent window.
992 static int get_parent(WId winid, Window *out_parent)
993 {
994  Window root, *children=0;
995  unsigned int nchildren;
996  int st = XQueryTree(tqt_xdisplay(), winid, &root, out_parent, &children, &nchildren);
997  if (st && children)
998  XFree(children);
999  return st;
1000 }
1001 
1002 // L1700: Embeds the window w into this QXEmbed widget.
1003 // See doc in qxembed.h.
1004 void QXEmbed::embed(WId w)
1005 {
1006  kdDebug() << "*** Embed " << w << " into " << winId() << ". window=" << window << endl;
1007  if (!w)
1008  return;
1009  // L1701: The has_window variable prevents embedding a same window twice.
1010  // ??? [what happens if one embed two windows into the same QXEmbed?]
1011  bool has_window = (w == window);
1012  window = w;
1013  if ( !has_window ) {
1014  KXErrorHandler errhandler; // make X BadWindow errors silent
1015  // L1710: Try hard to withdraw the window.
1016  // This makes sure that the window manager will
1017  // no longer try to manage this window.
1018  if ( !wstate_withdrawn(window) ) {
1019  XWithdrawWindow(tqt_xdisplay(), window, tqt_xscreen());
1020  TQApplication::flushX();
1021  // L1711: See L1610
1022  for (int i=0; i < 10000; ++i) {
1023  if (wstate_withdrawn(window)) {
1024  Window parent = 0;
1025  get_parent(w, &parent);
1026  if (parent == tqt_xrootwin()) break;
1027  }
1028  USLEEP(1000);
1029  }
1030  }
1031  // L1710: It would be sufficient in principle to reparent
1032  // window w into winId(). Everything else happens in L2020.
1033  // The following code might be useful when the X11 server takes
1034  // time to create the embedded application main window.
1035  Window parent = 0;
1036  get_parent(w, &parent);
1037  kdDebug() << TQString(TQString("> before reparent: parent=0x%1").arg(parent,0,16)) << endl;
1038  for (int i = 0; i < 50; i++) {
1039  // this is done once more when finishing embedding, but it's done also here
1040  // just in case we crash before reaching that place
1041  if( !d->xplain )
1042  XAddToSaveSet( tqt_xdisplay(), w );
1043  XReparentWindow(tqt_xdisplay(), w, winId(), 0, 0);
1044  if (get_parent(w, &parent) && parent == winId()) {
1045  kdDebug() << TQString(TQString("> Loop %1: ").arg(i))
1046  << TQString(TQString("> reparent of 0x%1").arg(w,0,16))
1047  << TQString(TQString(" into 0x%1").arg(winId(),0,16))
1048  << TQString(" successful") << endl;
1049  break;
1050  }
1051  kdDebug() << TQString(TQString("> Loop %1: ").arg(i))
1052  << TQString(TQString("> reparent of 0x%1").arg(w,0,16))
1053  << TQString(TQString(" into 0x%1").arg(winId(),0,16))
1054  << TQString(" failed") << endl;
1055  USLEEP(1000);
1056  }
1057  if( parent != winId()) // failed
1058  window = 0;
1059  }
1060 }
1061 
1062 // When a window is reparented into QXEmbed (or created inside of it), this function
1063 // sets up the actual embedding.
1064 void QXEmbed::handleEmbed()
1065 {
1066  // only XEMBED apps can survive crash,
1067  // see http://lists.kde.org/?l=kfm-devel&m=106752026501968&w=2
1068  if( !d->xplain )
1069  XAddToSaveSet( tqt_xdisplay(), window );
1070  XResizeWindow(tqt_xdisplay(), window, width(), height());
1071  XMapRaised(tqt_xdisplay(), window);
1072  // L2024: see L2900.
1073  sendSyntheticConfigureNotifyEvent();
1074  // L2025: ??? [any idea about drag&drop?]
1075  extraData()->xDndProxy = window;
1076  if ( parent() ) {
1077  // L2030: embedded window might have new size requirements.
1078  // see L2500, L2520, L2550.
1079  TQEvent * layoutHint = new TQEvent( TQEvent::LayoutHint );
1080  TQApplication::postEvent( parent(), layoutHint );
1081  }
1082  windowChanged( window );
1083  if (d->xplain) {
1084  // L2040: Activation has changed. Grab state might change. See L2800.
1085  checkGrab();
1086  if ( hasFocus() )
1087  // L2041: Send fake focus message to inform the client. See L1521.
1088  sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
1089  } else {
1090  // L2050: Send XEMBED messages (see L0670, L1312, L1322, L1530)
1091  sendXEmbedMessage( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
1092  if (isActiveWindow())
1093  sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE);
1094  else
1095  sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE);
1096  if ( hasFocus() )
1097  sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT );
1098  }
1099 }
1100 
1101 // L1800: Returns the window identifier of the embedded window
1102 WId QXEmbed::embeddedWinId() const
1103 {
1104  return window;
1105 }
1106 
1107 
1108 // L1900: Control Qt tab focus management.
1109 // See Qt documentation.
1110 bool QXEmbed::focusNextPrevChild( bool next )
1111 {
1112  if ( window )
1113  // L1901: Return false when there is an embedded window
1114  // When the user presses TAB, Qt will not change
1115  // the focus and pass the TAB key events to the QXEmbed widget.
1116  // These key events will be forwarded to the client (L1400, L1450)
1117  // who eventually will manage the tab focus (L0620) and possible
1118  // instruct us to call TQWidget::focusNextPrevChild (L2081).
1119  return false;
1120  else
1121  // L1920: Default behavior otherwise.
1122  return TQWidget::focusNextPrevChild( next );
1123 }
1124 
1125 
1126 // L2000: Filter for X11 events sent to the QXEmbed window.
1127 bool QXEmbed::x11Event( XEvent* e)
1128 {
1129  switch ( e->type ) {
1130  case DestroyNotify:
1131  if ( e->xdestroywindow.window == window ) {
1132  // L2005: Client window is being destroyed.
1133  window = 0;
1134  windowChanged( window );
1135  emit embeddedWindowDestroyed();
1136  }
1137  break;
1138  case CreateNotify:
1139  // A window was created inside of QXEmbed, handle it as embedded
1140  if( window == 0 ) { // only one window
1141  window = e->xcreatewindow.window;
1142  handleEmbed();
1143  }
1144  break;
1145  case ReparentNotify:
1146  if ( e->xreparent.window == d->focusProxy->winId() )
1147  break; // ignore proxy
1148  if ( window && e->xreparent.window == window &&
1149  e->xreparent.parent != winId() ) {
1150  // L2010: We lost the window
1151  window = 0;
1152  windowChanged( window );
1153  emit embeddedWindowDestroyed();
1154  // L2011: Remove window from save set
1155  // ??? [not sure it is good to touch this window since
1156  // someone else has taken control of it already.]
1157  if( !d->xplain )
1158  XRemoveFromSaveSet( tqt_xdisplay(), window );
1159  } else if ( e->xreparent.parent == winId()){
1160  if( window == 0 ) // something started embedding from the outside
1161  window = e->xreparent.window;
1162  // L2020: We got a window. Complete the embedding process.
1163  if( e->xreparent.window == window )
1164  handleEmbed();
1165  }
1166  break;
1167  case ButtonPress:
1168  if (d->xplain && d->xgrab) {
1169  // L2060: The passive grab has intercepted a mouse click
1170  // in the embedded client window. Take the focus.
1171 #ifdef USE_QT4
1172  setFocus();
1173 #else // USE_QT4
1174  TQFocusEvent::setReason( TQFocusEvent::Mouse );
1175  setFocus();
1176  TQFocusEvent::resetReason();
1177 #endif // USE_QT4
1178  // L2064: Resume X11 event processing.
1179  XAllowEvents(tqt_xdisplay(), ReplayPointer, CurrentTime);
1180  // L2065: Qt should not know about this.
1181  return true;
1182  }
1183  break;
1184  case ButtonRelease:
1185  if (d->xplain && d->xgrab) {
1186  // L2064: Resume X11 event processing after passive grab (see L2060)
1187  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime);
1188  return true;
1189  }
1190  break;
1191  case MapRequest:
1192  // L2070: Behave like a window manager.
1193  if ( window && e->xmaprequest.window == window )
1194  XMapRaised(tqt_xdisplay(), window );
1195  break;
1196  case ClientMessage:
1197  // L2080: This is where the QXEmbed object receives XEMBED
1198  // messaged from the client application.
1199  if ( e->xclient.format == 32 && e->xclient.message_type == xembed ) {
1200  long message = e->xclient.data.l[1];
1201  switch ( message ) {
1202  // L2081: Tab focus management. It is very important to call the
1203  // focusNextPrevChild() defined by TQWidget (not QXEmbed).
1204  // See L1901.
1205  case XEMBED_FOCUS_NEXT:
1206  TQWidget::focusNextPrevChild( true );
1207  break;
1208  case XEMBED_FOCUS_PREV:
1209  TQWidget::focusNextPrevChild( false );
1210  break;
1211  // L2085: The client asks for the focus.
1212  case XEMBED_REQUEST_FOCUS:
1213  if( ((QPublicWidget*)topLevelWidget())->topData()->embedded ) {
1214  focusMap->remove( topLevelWidget() );
1215  focusMap->insert( topLevelWidget(), new TQGuardedPtr<TQWidget>( this ));
1216 #ifdef USE_QT4
1217  WId window = ((QPublicWidget*)topLevelWidget())->effectiveWinId();
1218 #else // USE_QT4
1219  WId window = ((QPublicWidget*)topLevelWidget())->topData()->parentWinId;
1220 #endif // USE_QT4
1221  sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
1222  } else {
1223 #ifdef USE_QT4
1224  setFocus();
1225 #else // USE_QT4
1226  TQFocusEvent::setReason( TQFocusEvent::Mouse );
1227  setFocus();
1228  TQFocusEvent::resetReason();
1229 #endif // USE_QT4
1230  }
1231  break;
1232  default:
1233  break;
1234  }
1235  }
1236  break;
1237 
1238  case ConfigureRequest:
1239  // L2090: Client wants to change its geometry.
1240  // Just inform it that nothing has changed.
1241  if (e->xconfigurerequest.window == window)
1242  {
1243  sendSyntheticConfigureNotifyEvent();
1244  }
1245  break;
1246  case MotionNotify:
1247  // fall through, workaround for Qt 3.0 < 3.0.3
1248  case EnterNotify:
1249  // L2095: See L2200.
1250  if ( TQWhatsThis::inWhatsThisMode() )
1251  enterWhatsThisMode();
1252  break;
1253  default:
1254  break;
1255  }
1256  return false;
1257 }
1258 
1259 
1260 // L2200: Try to handle Qt's "what's this" mode. Broken.
1261 // "temporary, fix in Qt (Matthias, Mon Jul 17 15:20:55 CEST 2000"
1262 void QXEmbed::enterWhatsThisMode()
1263 {
1264  // L2210: When the what-s-this pointer enters the embedded window (L2095)
1265  // cancel what-s-this mode, and use a non stantard _NET_WM_ message
1266  // to instruct the embedded client to enter the "what's this" mode.
1267  // This works only one way...
1268  TQWhatsThis::leaveWhatsThisMode();
1269  if ( !context_help )
1270  context_help = XInternAtom( x11Display(), "_NET_WM_CONTEXT_HELP", false );
1271  sendClientMessage(window , tqt_wm_protocols, context_help );
1272 }
1273 
1274 
1275 // L2300: indicates that the embedded window has been changed.
1276 void QXEmbed::windowChanged( WId )
1277 {
1278 }
1279 
1280 
1281 // L2400: Utility function for clients that embed themselves.
1282 // This is client side code.
1283 bool QXEmbed::processClientCmdline( TQWidget* client, int& argc, char ** argv )
1284 {
1285  int myargc = argc;
1286  WId window = 0;
1287  int i, j;
1288 
1289  j = 1;
1290  for ( i=1; i<myargc; i++ ) {
1291  if ( argv[i] && *argv[i] != '-' ) {
1292  argv[j++] = argv[i];
1293  continue;
1294  }
1295  TQCString arg = argv[i];
1296  if ( !strcmp(arg,"-embed") && i < myargc-1 ) {
1297  TQCString s = argv[++i];
1298  window = s.toInt();
1299  } else
1300  argv[j++] = argv[i];
1301  }
1302  argc = j;
1303 
1304  if ( window ) {
1305  embedClientIntoWindow( client, window );
1306  return true;
1307  }
1308 
1309  return false;
1310 }
1311 
1312 
1313 // L2450: Utility function for clients that embed themselves.
1314 // This is client side code.
1315 void QXEmbed::embedClientIntoWindow(TQWidget* client, WId window)
1316 {
1317  initialize();
1318  XReparentWindow(tqt_xdisplay(), client->winId(), window, 0, 0);
1319  // L2451: These two lines are redundant. See L0680.
1320  ((QXEmbed*)client)->topData()->embedded = true;
1321 #ifdef USE_QT4
1322  // [FIXME]
1323  printf("[FIXME] WId not set in tdelibs/tdeui/qxembed.cpp\n");
1324 #else // USE_QT4
1325  ((QXEmbed*)client)->topData()->parentWinId = window;
1326 #endif // USE_QT4
1327  // L2452: This seems redundant because L2020 maps the window.
1328  // But calling show() might also set Qt internal flags.
1329  client->show();
1330 }
1331 
1332 
1333 
1334 // L2500: Specifies that this widget can use additional space,
1335 // and that it can survive on less than sizeHint().
1336 TQSizePolicy QXEmbed::sizePolicy() const
1337 {
1338  return TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding );
1339 }
1340 
1341 
1342 // L2520: Returns a size sufficient for the embedded window
1343 TQSize QXEmbed::sizeHint() const
1344 {
1345  return minimumSizeHint();
1346 }
1347 
1348 // L2550: Returns the minimum size specified by the embedded window.
1349 TQSize QXEmbed::minimumSizeHint() const
1350 {
1351  int minw = 0;
1352  int minh = 0;
1353  if ( window ) {
1354  XSizeHints size;
1355  long msize;
1356  if (XGetWMNormalHints(tqt_xdisplay(), window, &size, &msize)
1357  && ( size.flags & PMinSize) ) {
1358  minw = size.min_width;
1359  minh = size.min_height;
1360  }
1361  }
1362 
1363  return TQSize( minw, minh );
1364 }
1365 
1366 // L2600: Tells what shoud be done with the embedded window when
1367 // the embedding window is destroyed.
1368 void QXEmbed::setAutoDelete( bool b)
1369 {
1370  d->autoDelete = b;
1371 }
1372 
1373 // L2650: See L2600.
1374 bool QXEmbed::autoDelete() const
1375 {
1376  return d->autoDelete;
1377 }
1378 
1379 // L2700: See L2200.
1380 bool QXEmbed::customWhatsThis() const
1381 {
1382  return true;
1383 }
1384 
1385 // L2800: When using the XPLAIN protocol, this function maintains
1386 // a passive button grab when (1) the application is active
1387 // and (2) the Qt focus is not on the QXEmbed. This passive
1388 // grab intercepts button clicks in the client window and
1389 // give us chance to request the Qt focus (L2060).
1390 void QXEmbed::checkGrab()
1391 {
1392  if (d->xplain && isActiveWindow() && !hasFocus()) {
1393  if (! d->xgrab)
1394  XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, winId(),
1395  false, ButtonPressMask, GrabModeSync, GrabModeAsync,
1396  None, None );
1397  d->xgrab = true;
1398  } else {
1399  if (d->xgrab)
1400  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, winId() );
1401  d->xgrab = false;
1402  }
1403 }
1404 
1405 // L2900: This sends fake configure notify events to inform
1406 // the client about its window geometry. See L1390, L2024 and L2090.
1407 void QXEmbed::sendSyntheticConfigureNotifyEvent()
1408 {
1409  // L2910: It seems that the x and y coordinates are global.
1410  // But this is what ICCCM section 4.1.5 wants.
1411  // See http://lists.kde.org/?l=kfm-devel&m=107090222032378
1412  TQPoint globalPos = mapToGlobal(TQPoint(0,0));
1413  if (window) {
1414 #if 0
1415  XConfigureEvent c;
1416  memset(&c, 0, sizeof(c));
1417  c.type = ConfigureNotify;
1418  c.display = tqt_xdisplay();
1419  c.send_event = True;
1420  c.event = window;
1421  c.window = window;
1422  c.x = globalPos.x();
1423  c.y = globalPos.y();
1424  c.width = width();
1425  c.height = height();
1426  c.border_width = 0;
1427  c.above = None;
1428  c.override_redirect = 0;
1429  XSendEvent( tqt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c );
1430 #endif
1431  // Yes, this doesn't make sense at all. See the commit message.
1432  XSetWindowBorderWidth( tqt_xdisplay(), window, 1 );
1433  XSetWindowBorderWidth( tqt_xdisplay(), window, 0 );
1434  }
1435 }
1436 
1437 // L3000: One should not call TQWidget::reparent after embedding a window.
1438 void QXEmbed::reparent( TQWidget * parent, WFlags f, const TQPoint & p, bool showIt )
1439 {
1440  // TQWidget::reparent() destroys the old X Window for the widget, and
1441  // creates a new one, thus QXEmbed after reparenting is no longer the
1442  // parent of the embedded window. I think reparenting of QXEmbed can be
1443  // done only by a mistake, so just complain.
1444  Q_ASSERT( !window );
1445  TQWidget::reparent( parent, f, p, showIt );
1446 }
1447 
1448 // for KDE
1449 #include "qxembed.moc"
1450 #endif // Q_WS_X11
None
kdDebug
kdbgstream kdDebug(int area=0)
KXErrorHandler
KStdAction::revert
TDEAction * revert(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name)
Revert the current document to the last saved version (essentially will undo all changes).
Definition: kstdaction.cpp:152
endl
kndbgstream & endl(kndbgstream &s)

tdeui

Skip menu "tdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeui

Skip menu "tdeui"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeui by doxygen 1.8.8
This website is maintained by Timothy Pearson.