• 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 TQ_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_tqt_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_tqt_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 ( tqApp->focusWidget() == 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  WId window = ((QPublicWidget*)tqApp->focusWidget()->topLevelWidget())->topData()->parentWinId;
323  focusMap->remove( tqApp->focusWidget()->topLevelWidget() );
324  sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
325  } else if ( fe->reason() == TQFocusEvent::ActiveWindow ) {
326  // L0615: Both the embedder and the embedded client became active.
327  // But we do not know whether the QXEmbed widget has the Qt focus.
328  // So we clear the Qt focus for now. If indeed the QXEmbed widget
329  // has the focus, it will receive a FocusIn message (L1530) and
330  // tell us to restore the focus (L0680, L0683).
331  focusMap->remove( tqApp->focusWidget()->topLevelWidget() );
332  focusMap->insert( tqApp->focusWidget()->topLevelWidget(),
333  new TQGuardedPtr<TQWidget>(tqApp->focusWidget()->topLevelWidget()->focusWidget() ) );
334  // L0616: tqApp->focusWidget() might belong to a modal dialog and not be
335  // equal to tqApp->focusWidget()->topLevelWidget()->focusWidget() !
336  tqApp->focusWidget()->clearFocus();
337  // L0617: ??? [why not {obeyFocus=false; return true;} here?]
338  }
339  obeyFocus = false;
340  }
341  break;
342  case TQEvent::KeyPress:
343  if (tqApp->focusWidget() == o &&
344  ((QPublicWidget*)tqApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
345  // L0620: The following code replaces the Qt code that
346  // handles focus focus changes with the tab key. See the
347  // XEMBED specification for details. The keypress event
348  // arrives here after an interesting itinerary. It is first
349  // saved in the embedding application (L0660). After being
350  // rejected for tab navigation in the embedding application
351  // (L1901), it gets forwarded to the embedded client
352  // (L1400) and arrives here. Depending on the status of
353  // the tab chain in the embedded client, focus navigation
354  // messages are sent back to the embedding application
355  // (L0653, L0654) which then performs tab navigation
356  // (L2081).
357  TQKeyEvent *k = (TQKeyEvent *)e;
358  TQWidget *w = tqApp->focusWidget();
359  // L0621: The following tests are copied from TQWidget::event().
360  bool res = false;
361  bool tabForward = true;
362  if ( !(k->state() & ControlButton || k->state() & AltButton) ) {
363  if ( k->key() == Key_Backtab || (k->key() == Key_Tab && (k->state() & ShiftButton)) ) {
364  TQFocusEvent::setReason( TQFocusEvent::Backtab );
365  res = ((QPublicWidget*)w)->focusNextPrev( tabForward = false );
366  TQFocusEvent::resetReason();
367  } else if ( k->key() == Key_Tab ) {
368  TQFocusEvent::setReason( TQFocusEvent::Tab );
369  res = ((QPublicWidget*)w)->focusNextPrev( tabForward = true );
370  TQFocusEvent::resetReason();
371  }
372  }
373  if (res) {
374  // L0625: We changed the focus because of tab/backtab key
375  // Now check whether we have been looping around.
376  TQFocusData *fd = ((QPublicWidget*)w)->focusData();
377  WId window = ((QPublicWidget*)w->topLevelWidget())->topData()->parentWinId;
378  TQWidget *cw = 0;
379  TQWidget *fw = fd->home();
380  if (tabForward && window) {
381  while (cw != w && cw != fw && cw != w->topLevelWidget())
382  cw = fd->prev();
383  if (cw != w)
384  sendXEmbedMessage( window, XEMBED_FOCUS_NEXT );
385  } else if (window) {
386  while (cw != w && cw != fw && cw != w->topLevelWidget())
387  cw = fd->next();
388  if (cw != w)
389  sendXEmbedMessage( window, XEMBED_FOCUS_PREV );
390  }
391  // L0628: Qt should no longer process this event.
392  return true;
393  }
394  }
395  break;
396  default:
397  break;
398  }
399  // L0640: Application gets to see the events anyway.
400  return false;
401 }
402 
403 // L0650: This filter receives all XEvents in both the client and the embedder.
404 // Most of it involves the embedded client (except L0660, L0671).
405 static int qxembed_x11_event_filter( XEvent* e)
406 {
407  switch ( e->type ) {
408  case XKeyPress:
409  case XKeyRelease: {
410  // L0660: This is for the embedding side (L1450).
411  last_key_event = e->xkey;
412  break;
413  }
414  case ClientMessage:
415  if ( e->xclient.message_type == xembed ) {
416  // L0670: This is where the XEmbed messages are
417  // processed on the client side.
418  Time msgtime = (Time) e->xclient.data.l[0];
419  long message = e->xclient.data.l[1];
420  long detail = e->xclient.data.l[2];
421  // L0671: Keep Qt message time up to date
422  if ( msgtime > get_tqt_x_time() )
423  set_tqt_x_time(msgtime);
424  TQWidget* w = TQWidget::find( e->xclient.window );
425  if ( !w )
426  break;
427  switch ( message) {
428  case XEMBED_EMBEDDED_NOTIFY: {
429  // L0675: We just have been embedded into a XEMBED aware widget.
430  TQTLWExtra *extra = ((QPublicWidget*)w->topLevelWidget())->topData();
431  extra->embedded = 1;
432  extra->parentWinId = e->xclient.data.l[3];
433  w->topLevelWidget()->show();
434  break;
435  }
436  case XEMBED_WINDOW_ACTIVATE: {
437  // L0676: Embedding window becomes active. Send a fake XFocusIn
438  // to convince Qt that we are active as well. Qt will send
439  // us a focus notification (L0615) that we will intercept to
440  // ensure that we have no Qt focus widget yet. The Qt focus
441  // widget might later be set in L0680.
442  XEvent ev;
443  memset(&ev, 0, sizeof(ev));
444  ev.xfocus.display = tqt_xdisplay();
445  ev.xfocus.type = XFocusIn;
446  ev.xfocus.window = w->topLevelWidget()->winId();
447  ev.xfocus.mode = NotifyNormal;
448  ev.xfocus.detail = NotifyAncestor;
449  tqApp->x11ProcessEvent( &ev );
450  }
451  break;
452  case XEMBED_WINDOW_DEACTIVATE: {
453  // L0677: Embedding window becomes inactive. Send a fake XFocusOut
454  // event to convince Qt that we no longer are active. We will
455  // receive extra Qt FocusOut events but we do not care.
456  XEvent ev;
457  memset(&ev, 0, sizeof(ev));
458  ev.xfocus.display = tqt_xdisplay();
459  ev.xfocus.type = XFocusOut;
460  ev.xfocus.window = w->topLevelWidget()->winId();
461  ev.xfocus.mode = NotifyNormal;
462  ev.xfocus.detail = NotifyAncestor;
463  tqApp->x11ProcessEvent( &ev );
464  }
465  break;
466  case XEMBED_FOCUS_IN:
467  // L0680: Embedding application gives us the focus.
468  {
469  // L0681: Search saved focus widget.
470  TQWidget* focusCurrent = 0;
471  TQGuardedPtr<TQWidget>* fw = focusMap->find( w->topLevelWidget() );
472  if ( fw ) {
473  focusCurrent = *fw;
474  // L0682: Remove it from the map
475  focusMap->remove( w->topLevelWidget() );
476  }
477  switch ( detail ) {
478  case XEMBED_FOCUS_CURRENT:
479  // L0683: Set focus on saved focus widget
480  if ( focusCurrent ) {
481  focusCurrent->setFocus();
482  if( QXEmbed* emb = dynamic_cast< QXEmbed* >( focusCurrent ))
483  emb->updateEmbeddedFocus( true );
484  }
485  else if ( !w->topLevelWidget()->focusWidget() )
486  w->topLevelWidget()->setFocus();
487  break;
488  case XEMBED_FOCUS_FIRST:
489  {
490  // L0684: Search first widget in tab chain
491  TQFocusEvent::setReason( TQFocusEvent::Tab );
492  w->topLevelWidget()->setFocus();
493  ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(true);
494  TQFocusEvent::resetReason();
495  }
496  break;
497  case XEMBED_FOCUS_LAST:
498  {
499  // L0686: Search last widget in tab chain
500  TQFocusEvent::setReason( TQFocusEvent::Backtab );
501  w->topLevelWidget()->setFocus();
502  ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(false);
503  TQFocusEvent::resetReason();
504  }
505  break;
506  default:
507  break;
508  }
509  }
510  break;
511  case XEMBED_FOCUS_OUT:
512  // L0688: Embedding application takes the focus away
513  // We first record what the focus widget was
514  // and clear the Qt focus.
515  if ( w->topLevelWidget()->focusWidget() ) {
516  if( QXEmbed* emb = dynamic_cast< QXEmbed* >( w->topLevelWidget()->focusWidget()))
517  emb->updateEmbeddedFocus( false );
518  focusMap->insert( w->topLevelWidget(),
519  new TQGuardedPtr<TQWidget>(w->topLevelWidget()->focusWidget() ) );
520  w->topLevelWidget()->focusWidget()->clearFocus();
521  }
522  break;
523  default:
524  break;
525  }
526  } else if ( e->xclient.format == 32 && e->xclient.message_type ) {
527  if ( e->xclient.message_type == tqt_wm_protocols ) {
528  TQWidget* w = TQWidget::find( e->xclient.window );
529  if ( !w )
530  break;
531  // L0690: This is for the embedding side!
532  // See L0902 for more information about the focus proxy.
533  // Window manager may send WM_TAKE_FOCUS messages to the
534  // embedding application to indicate that it becomes active.
535  // But this also suggests that the window manager has
536  // changed the X11 focus. We want to make sure it goes
537  // to the focus proxy window eventually.
538  Atom a = e->xclient.data.l[0];
539  if ( a == tqt_wm_take_focus ) {
540  // L0695: update Qt message time variable
541  if ( (ulong) e->xclient.data.l[1] > get_tqt_x_time() )
542  set_tqt_x_time(e->xclient.data.l[1]);
543  // L0696: There is no problem when the window is not active.
544  // Qt will generate a WindowActivate event that will
545  // do the job (L1310). This does not happen if the
546  // window is already active. So we simulate it.
547  if ( w->isActiveWindow() ) {
548  TQEvent e( TQEvent::WindowActivate );
549  TQApplication::sendEvent( w, &e );
550  }
551  }
552  }
553  }
554  break;
555  default:
556  break;
557  }
558  // L0698: The next x11 filter
559  if ( oldFilter )
560  return oldFilter( e );
561  // L0699: Otherwise process the event as usual.
562  return false;
563 }
564 
565 
566 
567 // L0700: Install the xembed filters in both client and embedder sides.
568 // This function is called automatically when using
569 // embedClientIntoWindow() or creating an instance of QXEmbed You may
570 // have to call it manually for a client when using embedder-side
571 // embedding, though.
572 void QXEmbed::initialize()
573 {
574  static bool is_initialized = false;
575  if ( is_initialized )
576  return;
577 
578  // L0710: Atom used by the XEMBED protocol.
579  xembed = XInternAtom( tqt_xdisplay(), "_XEMBED", false );
580  // L0720: Install low level filter for X11 events (L0650)
581  oldFilter = tqt_set_x11_event_filter( qxembed_x11_event_filter );
582  // L0730: See L0610 for an explanation about focusMap.
583  focusMap = new TQPtrDict<TQGuardedPtr<TQWidget> >;
584  focusMap->setAutoDelete( true );
585  // L0740: Create client side application wide event filter (L0610)
586  filter = new QXEmbedAppFilter;
587 
588  is_initialized = true;
589 }
590 
591 
592 
593 
594 
595 // ------------------------------------------------------------
596 // L0800: MOST OF WHAT FOLLOWS CONCERNS THE EMBEDDER SIDE.
597 // Things that happen inside a Qt application that contain
598 // a QXEmbed widget for embedding other applications.
599 // This applies to both the XEMBED and XPLAIN protocols.
600 // Deviations are commented below.
601 
602 
603 
604 // L0810: Class QXEmbed.
605 // A QXEmbed widget serves as an embedder that can manage one single
606 // embedded X-window. These so-called client windows can be arbitrary
607 // Qt or non Qt applications. There are two different ways of using
608 // QXEmbed, from the client side or from the embedder's side.
609 
610 
611 // L0900: Constructs a xembed widget.
612 QXEmbed::QXEmbed(TQWidget *parent, const char *name, WFlags f)
613  : TQWidget(parent, name, f)
614 {
615  // L0901: Create private data. See L0100.
616  d = new QXEmbedData;
617  // L0902: Create focus proxy widget. See XEmbed specification.
618  // Each QXEmbed widget has a focus proxy window. Every single
619  // QXEmbed widget tries to force its focus proxy window onto the
620  // whole embedding application. They compete between themselves and
621  // against Qt (L0690, L0914, L1040, L1310, L1510, L1580).
622  // This would be much simpler if implemented within Qt.
623  d->focusProxy = new TQWidget( topLevelWidget(), "xembed_focus" );
624  d->focusProxy->setGeometry( -1, -1, 1, 1 );
625  d->focusProxy->show();
626  // make sure it's shown - for XSetInputFocus
627  TQApplication::sendPostedEvents( d->focusProxy, 0 );
628  // L0903: Install the client side event filters
629  // because they also provide services for the embedder side
630  // See L0660, L0671, L0685.
631  initialize();
632  window = 0;
633  setFocusPolicy(TQWidget::StrongFocus);
634  setKeyCompression( false );
635 
636  // L0910: Trick Qt to create extraData();
637  (void) topData();
638 
639  // L0912: We are mostly interested in SubstructureNotify
640  // This is sent when something happens to the children of
641  // the X11 window associated with the QXEmbed widget.
642  XSelectInput(tqt_xdisplay(), winId(),
643  KeyPressMask | KeyReleaseMask |
644  ButtonPressMask | ButtonReleaseMask |
645  KeymapStateMask |
646  ButtonMotionMask |
647  PointerMotionMask | // may need this, too
648  EnterWindowMask | LeaveWindowMask |
649  FocusChangeMask |
650  ExposureMask |
651  StructureNotifyMask |
652  SubstructureRedirectMask |
653  SubstructureNotifyMask
654  );
655  // L0913: all application events pass through eventFilter().
656  // This is mostly used to force the X11 focus on the
657  // proxy focus window. See L1300.
658  topLevelWidget()->installEventFilter( this );
659  tqApp->installEventFilter( this );
660 
661  // L0914: Start moving the X11 focus on the focus proxy window.
662  // See L1581 to know why we do not use isActiveWindow().
663  if ( tqApp->activeWindow() == topLevelWidget() )
664  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
665  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
666  RevertToParent, get_tqt_x_time() );
667  // L0915: ??? [drag&drop?]
668  setAcceptDrops( true );
669 }
670 
671 // L1000: Destructor must dispose of the embedded client window.
672 QXEmbed::~QXEmbed()
673 {
674  // L1010: Make sure no pointer grab is left.
675  if ( d && d->xgrab)
676  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, winId() );
677  if ( window && ( autoDelete() || !d->xplain ))
678  {
679  // L1021: Hide the window and safely reparent it into the root,
680  // otherwise it would be destroyed by X11 together
681  // with this QXEmbed's window.
682 #if 0
683 // TODO: The proper XEmbed way would be to unmap the window, and the embedded
684 // app would detect the embedding has ended, and do whatever it finds appropriate.
685 // However, QXEmbed currently doesn't provide support for this detection,
686 // so for the time being, it's better to leave the window mapped as toplevel window.
687 // This will be ever more complicated with the systray windows, as the simple API
688 // for them (KWin::setSystemTrayWindowFor()) doesn't make it possible to detect
689 // themselves they have been released from systray, but KWin requires them
690 // to be visible to allow next Kicker instance to swallow them.
691 // See also below the L1022 comment.
692 // XUnmapWindow( tqt_xdisplay(), window );
693 #else
694  if( autoDelete())
695  XUnmapWindow( tqt_xdisplay(), window );
696 #endif
697  XReparentWindow(tqt_xdisplay(), window, tqt_xrootwin(), 0, 0);
698  if( !d->xplain )
699  XRemoveFromSaveSet( tqt_xdisplay(), window );
700  if( d->mapAfterRelease )
701  XMapWindow( tqt_xdisplay(), window );
702  XSync(tqt_xdisplay(), false);
703  // L1022: Send the WM_DELETE_WINDOW message
704  if( autoDelete() /*&& d->xplain*/ )
705  // This sendDelete should only apply to XPLAIN.
706  // XEMBED apps are supposed to detect when the embedding ends.
707  // ??? [We do not do this detection yet!
708  // So we sendDelete() instead.]
709  sendDelete();
710  }
711  window = 0;
712  // L01040: Our focus proxy window will be destroyed as well.
713  // Make sure that the X11 focus is not lost in the process.
714  Window focus;
715  int revert;
716  XGetInputFocus( tqt_xdisplay(), &focus, &revert );
717  if( focus == d->focusProxy->winId())
718  XSetInputFocus( tqt_xdisplay(), topLevelWidget()->winId(), RevertToParent, get_tqt_x_time() );
719  // L01045: Delete our private data.
720  delete d;
721 }
722 
723 
724 // L1050: Sends a WM_DELETE_WINDOW message to the embedded window. This is
725 // what typically happens when you click on the close button of a
726 // window manager decoration.
727 void QXEmbed::sendDelete( void )
728 {
729  if (window)
730  {
731  sendClientMessage(window, tqt_wm_protocols, tqt_wm_delete_window);
732  XFlush( tqt_xdisplay() );
733  }
734 }
735 
736 // L1100: Sets the protocol used for embedding windows.
737 // This function must be called before embedding a window.
738 // Protocol XEMBED provides maximal functionality (focus, tabs, etc)
739 // but requires explicit cooperation from the embedded window.
740 // Protocol XPLAIN provides maximal compatibility with
741 // embedded applications that do not support the XEMBED protocol.
742 // The default is XEMBED.
743 void QXEmbed::setProtocol( Protocol proto )
744 {
745  if (!window) {
746  d->xplain = false;
747  if (proto == XPLAIN)
748  d->xplain = true;
749  }
750 }
751 
752 // L1150: Returns the protocol used for embedding the current window.
753 QXEmbed::Protocol QXEmbed::protocol()
754 {
755  if (d->xplain)
756  return XPLAIN;
757  return XEMBED;
758 }
759 
760 
761 // L1200: QXEmbed widget size changes: resize embedded window.
762 void QXEmbed::resizeEvent(TQResizeEvent*)
763 {
764  if (window)
765  XResizeWindow(tqt_xdisplay(), window, width(), height());
766 }
767 
768 // L1250: QXEmbed widget is shown: make sure embedded window is visible.
769 void QXEmbed::showEvent(TQShowEvent*)
770 {
771  if (window)
772  XMapRaised(tqt_xdisplay(), window);
773 }
774 
775 
776 // L1300: This event filter sees all application events (L0913).
777 bool QXEmbed::eventFilter( TQObject *o, TQEvent * e)
778 {
779 
780  switch ( e->type() ) {
781  case TQEvent::WindowActivate:
782  if ( o == topLevelWidget() ) {
783  // L1310: Qt thinks the application window has just been activated.
784  // Make sure the X11 focus is on the focus proxy window. See L0686.
785  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
786  if (! hasFocus() )
787  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
788  RevertToParent, get_tqt_x_time() );
789  if (d->xplain)
790  // L1311: Activation has changed. Grab state might change. See L2800.
791  checkGrab();
792  else
793  // L1312: Let the client know that we just became active
794  sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE );
795  }
796  break;
797  case TQEvent::WindowDeactivate:
798  if ( o == topLevelWidget() ) {
799  if (d->xplain)
800  // L1321: Activation has changed. Grab state might change. See L2800.
801  checkGrab();
802  else
803  // L1322: Let the client know that we are no longer active
804  sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE );
805  }
806  break;
807  case TQEvent::Move:
808  {
809  TQWidget* pos = this;
810  while( pos != o && pos != topLevelWidget())
811  pos = pos->parentWidget();
812  if( pos == o ) {
813  // L1390: Send fake configure notify events whenever the
814  // global position of the client changes. See L2900.
815  TQPoint globalPos = mapToGlobal(TQPoint(0,0));
816  if (globalPos != d->lastPos) {
817  d->lastPos = globalPos;
818  sendSyntheticConfigureNotifyEvent();
819  }
820  }
821  }
822  break;
823  default:
824  break;
825  }
826  return false;
827 }
828 
829 // L1350: ??? [why this?]
830 bool QXEmbed::event( TQEvent * e)
831 {
832  return TQWidget::event( e );
833 }
834 
835 // L1400: Forward keypress event to the client
836 // Receiving a Qt key event indicates that
837 // the QXEmbed object has the Qt focus.
838 // The X11 event that caused the Qt key event
839 // must be forwarded to the client.
840 // See L0660.
841 void QXEmbed::keyPressEvent( TQKeyEvent *)
842 {
843  if (!window)
844  return;
845  last_key_event.window = window;
846  XSendEvent(tqt_xdisplay(), window, false, KeyPressMask, (XEvent*)&last_key_event);
847 
848 }
849 
850 // L1450: Forward keyrelease event to the client.
851 // See comment L1400.
852 void QXEmbed::keyReleaseEvent( TQKeyEvent *)
853 {
854  if (!window)
855  return;
856  last_key_event.window = window;
857  XSendEvent(tqt_xdisplay(), window, false, KeyReleaseMask, (XEvent*)&last_key_event);
858 }
859 
860 // L1500: Handle Qt focus in event.
861 void QXEmbed::focusInEvent( TQFocusEvent * e ){
862  if (!window)
863  return;
864  // L1510: This is a good time to set the X11 focus on the focus proxy window.
865  // Except if the the embedding application itself is embedded into another.
866  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
867  if ( tqApp->activeWindow() == topLevelWidget() )
868  // L1511: Alter X focus only when window is active.
869  // This is dual safety here because FocusIn implies this.
870  // But see L1581 for an example where this really matters.
871  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
872  RevertToParent, get_tqt_x_time() );
873  if (d->xplain) {
874  // L1520: Qt focus has changed. Grab state might change. See L2800.
875  checkGrab();
876  // L1521: Window managers activate applications by setting the X11 focus.
877  // We cannot do this (see L1510) but we can send a fake focus event
878  // and forward the X11 key events ourselves (see L1400, L1450).
879  sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
880  } else {
881  // L1530: No need for fake events with XEMBED.
882  // Just inform the client. It knows what to do.
883  int detail = XEMBED_FOCUS_CURRENT;
884  // L1531: When the focus change is caused by the tab key,
885  // the client must select the first (or last) widget of
886  // its own tab chain.
887  if ( e->reason() == TQFocusEvent::Tab )
888  detail = XEMBED_FOCUS_FIRST;
889  else if ( e->reason() == TQFocusEvent::Backtab )
890  detail = XEMBED_FOCUS_LAST;
891  sendXEmbedMessage( window, XEMBED_FOCUS_IN, detail);
892  }
893 }
894 
895 // L1550: Handle Qt focus out event.
896 void QXEmbed::focusOutEvent( TQFocusEvent * ){
897  if (!window)
898  return;
899  if (d->xplain) {
900  // L1560: Qt focus has changed. Grab state might change. See L2800.
901  checkGrab();
902  // L1561: Send fake focus out message. See L1521.
903  sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer );
904  } else {
905  // L1570: Send XEMBED focus out message. See L1531.
906  sendXEmbedMessage( window, XEMBED_FOCUS_OUT );
907  }
908  // L1580: The QXEmbed object might loose the focus because its
909  // toplevel window looses the X11 focus and is no longer active,
910  // or simply because the Qt focus has been moved to another widget.
911  // In the latter case only, we want to make sure that the X11 focus
912  // is properly set to the X11 focus widget. We do this because
913  // the client application might have moved the X11 focus after
914  // receiving the fake focus messages.
915  if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
916  if ( tqApp->activeWindow() == topLevelWidget() )
917  // L1581: Alter X focus only when window is active.
918  // The test above is not the same as isActiveWindow().
919  // Function isActiveWindow() also returns true when a modal
920  // dialog child of this window is active.
921  XSetInputFocus( tqt_xdisplay(), d->focusProxy->winId(),
922  RevertToParent, get_tqt_x_time() );
923 }
924 
925 
926 // When QXEmbed has TQt focus and gets/loses X focus, make sure the client knows
927 // about the state of the focus.
928 void QXEmbed::updateEmbeddedFocus( bool hasfocus ){
929  if (!window || d->xplain)
930  return;
931  if( hasfocus )
932  sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
933  else
934  sendXEmbedMessage( window, XEMBED_FOCUS_OUT);
935 }
936 
937 // L1600: Helper for QXEmbed::embed()
938 // Check whether a window is in withdrawn state.
939 static bool wstate_withdrawn( WId winid )
940 {
941  Atom type;
942  int format;
943  unsigned long length, after;
944  unsigned char *data;
945  int r = XGetWindowProperty( tqt_xdisplay(), winid, tqt_wm_state, 0, 2,
946  false, AnyPropertyType, &type, &format,
947  &length, &after, &data );
948  bool withdrawn = true;
949  // L1610: Non managed windows have no WM_STATE property.
950  // Returning true ensures that the loop L1711 stops.
951  if ( r == Success && data && format == 32 ) {
952  TQ_UINT32 *wstate = (TQ_UINT32*)data;
953  withdrawn = (*wstate == WithdrawnState );
954  XFree( (char *)data );
955  }
956  return withdrawn;
957 }
958 
959 // L1650: Helper for QXEmbed::embed()
960 // Get the X11 id of the parent window.
961 static int get_parent(WId winid, Window *out_parent)
962 {
963  Window root, *children=0;
964  unsigned int nchildren;
965  int st = XQueryTree(tqt_xdisplay(), winid, &root, out_parent, &children, &nchildren);
966  if (st && children)
967  XFree(children);
968  return st;
969 }
970 
971 // L1700: Embeds the window w into this QXEmbed widget.
972 // See doc in qxembed.h.
973 void QXEmbed::embed(WId w)
974 {
975  kdDebug() << "*** Embed " << w << " into " << winId() << ". window=" << window << endl;
976  if (!w)
977  return;
978  // L1701: The has_window variable prevents embedding a same window twice.
979  // ??? [what happens if one embed two windows into the same QXEmbed?]
980  bool has_window = (w == window);
981  window = w;
982  if ( !has_window ) {
983  KXErrorHandler errhandler; // make X BadWindow errors silent
984  // L1710: Try hard to withdraw the window.
985  // This makes sure that the window manager will
986  // no longer try to manage this window.
987  if ( !wstate_withdrawn(window) ) {
988  XWithdrawWindow(tqt_xdisplay(), window, tqt_xscreen());
989  TQApplication::flushX();
990  // L1711: See L1610
991  for (int i=0; i < 10000; ++i) {
992  if (wstate_withdrawn(window)) {
993  Window parent = 0;
994  get_parent(w, &parent);
995  if (parent == tqt_xrootwin()) break;
996  }
997  USLEEP(1000);
998  }
999  }
1000  // L1710: It would be sufficient in principle to reparent
1001  // window w into winId(). Everything else happens in L2020.
1002  // The following code might be useful when the X11 server takes
1003  // time to create the embedded application main window.
1004  Window parent = 0;
1005  get_parent(w, &parent);
1006  kdDebug() << TQString(TQString("> before reparent: parent=0x%1").arg(parent,0,16)) << endl;
1007  for (int i = 0; i < 50; i++) {
1008  // this is done once more when finishing embedding, but it's done also here
1009  // just in case we crash before reaching that place
1010  if( !d->xplain )
1011  XAddToSaveSet( tqt_xdisplay(), w );
1012  XReparentWindow(tqt_xdisplay(), w, winId(), 0, 0);
1013  if (get_parent(w, &parent) && parent == winId()) {
1014  kdDebug() << TQString(TQString("> Loop %1: ").arg(i))
1015  << TQString(TQString("> reparent of 0x%1").arg(w,0,16))
1016  << TQString(TQString(" into 0x%1").arg(winId(),0,16))
1017  << TQString(" successful") << endl;
1018  break;
1019  }
1020  kdDebug() << TQString(TQString("> Loop %1: ").arg(i))
1021  << TQString(TQString("> reparent of 0x%1").arg(w,0,16))
1022  << TQString(TQString(" into 0x%1").arg(winId(),0,16))
1023  << TQString(" failed") << endl;
1024  USLEEP(1000);
1025  }
1026  if( parent != winId()) // failed
1027  window = 0;
1028  }
1029 }
1030 
1031 // When a window is reparented into QXEmbed (or created inside of it), this function
1032 // sets up the actual embedding.
1033 void QXEmbed::handleEmbed()
1034 {
1035  // only XEMBED apps can survive crash,
1036  // see http://lists.kde.org/?l=kfm-devel&m=106752026501968&w=2
1037  if( !d->xplain )
1038  XAddToSaveSet( tqt_xdisplay(), window );
1039  XResizeWindow(tqt_xdisplay(), window, width(), height());
1040  XMapRaised(tqt_xdisplay(), window);
1041  // L2024: see L2900.
1042  sendSyntheticConfigureNotifyEvent();
1043  // L2025: ??? [any idea about drag&drop?]
1044  extraData()->xDndProxy = window;
1045  if ( parent() ) {
1046  // L2030: embedded window might have new size requirements.
1047  // see L2500, L2520, L2550.
1048  TQEvent * layoutHint = new TQEvent( TQEvent::LayoutHint );
1049  TQApplication::postEvent( parent(), layoutHint );
1050  }
1051  windowChanged( window );
1052  if (d->xplain) {
1053  // L2040: Activation has changed. Grab state might change. See L2800.
1054  checkGrab();
1055  if ( hasFocus() )
1056  // L2041: Send fake focus message to inform the client. See L1521.
1057  sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
1058  } else {
1059  // L2050: Send XEMBED messages (see L0670, L1312, L1322, L1530)
1060  sendXEmbedMessage( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
1061  if (isActiveWindow())
1062  sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE);
1063  else
1064  sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE);
1065  if ( hasFocus() )
1066  sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT );
1067  }
1068 }
1069 
1070 // L1800: Returns the window identifier of the embedded window
1071 WId QXEmbed::embeddedWinId() const
1072 {
1073  return window;
1074 }
1075 
1076 
1077 // L1900: Control Qt tab focus management.
1078 // See Qt documentation.
1079 bool QXEmbed::focusNextPrevChild( bool next )
1080 {
1081  if ( window )
1082  // L1901: Return false when there is an embedded window
1083  // When the user presses TAB, Qt will not change
1084  // the focus and pass the TAB key events to the QXEmbed widget.
1085  // These key events will be forwarded to the client (L1400, L1450)
1086  // who eventually will manage the tab focus (L0620) and possible
1087  // instruct us to call TQWidget::focusNextPrevChild (L2081).
1088  return false;
1089  else
1090  // L1920: Default behavior otherwise.
1091  return TQWidget::focusNextPrevChild( next );
1092 }
1093 
1094 
1095 // L2000: Filter for X11 events sent to the QXEmbed window.
1096 bool QXEmbed::x11Event( XEvent* e)
1097 {
1098  switch ( e->type ) {
1099  case DestroyNotify:
1100  if ( e->xdestroywindow.window == window ) {
1101  // L2005: Client window is being destroyed.
1102  window = 0;
1103  windowChanged( window );
1104  emit embeddedWindowDestroyed();
1105  }
1106  break;
1107  case CreateNotify:
1108  // A window was created inside of QXEmbed, handle it as embedded
1109  if( window == 0 ) { // only one window
1110  window = e->xcreatewindow.window;
1111  handleEmbed();
1112  }
1113  break;
1114  case ReparentNotify:
1115  if ( e->xreparent.window == d->focusProxy->winId() )
1116  break; // ignore proxy
1117  if ( window && e->xreparent.window == window &&
1118  e->xreparent.parent != winId() ) {
1119  // L2010: We lost the window
1120  window = 0;
1121  windowChanged( window );
1122  emit embeddedWindowDestroyed();
1123  // L2011: Remove window from save set
1124  // ??? [not sure it is good to touch this window since
1125  // someone else has taken control of it already.]
1126  if( !d->xplain )
1127  XRemoveFromSaveSet( tqt_xdisplay(), window );
1128  } else if ( e->xreparent.parent == winId()){
1129  if( window == 0 ) // something started embedding from the outside
1130  window = e->xreparent.window;
1131  // L2020: We got a window. Complete the embedding process.
1132  if( e->xreparent.window == window )
1133  handleEmbed();
1134  }
1135  break;
1136  case ButtonPress:
1137  if (d->xplain && d->xgrab) {
1138  // L2060: The passive grab has intercepted a mouse click
1139  // in the embedded client window. Take the focus.
1140  TQFocusEvent::setReason( TQFocusEvent::Mouse );
1141  setFocus();
1142  TQFocusEvent::resetReason();
1143  // L2064: Resume X11 event processing.
1144  XAllowEvents(tqt_xdisplay(), ReplayPointer, CurrentTime);
1145  // L2065: Qt should not know about this.
1146  return true;
1147  }
1148  break;
1149  case ButtonRelease:
1150  if (d->xplain && d->xgrab) {
1151  // L2064: Resume X11 event processing after passive grab (see L2060)
1152  XAllowEvents(tqt_xdisplay(), SyncPointer, CurrentTime);
1153  return true;
1154  }
1155  break;
1156  case MapRequest:
1157  // L2070: Behave like a window manager.
1158  if ( window && e->xmaprequest.window == window )
1159  XMapRaised(tqt_xdisplay(), window );
1160  break;
1161  case ClientMessage:
1162  // L2080: This is where the QXEmbed object receives XEMBED
1163  // messaged from the client application.
1164  if ( e->xclient.format == 32 && e->xclient.message_type == xembed ) {
1165  long message = e->xclient.data.l[1];
1166  switch ( message ) {
1167  // L2081: Tab focus management. It is very important to call the
1168  // focusNextPrevChild() defined by TQWidget (not QXEmbed).
1169  // See L1901.
1170  case XEMBED_FOCUS_NEXT:
1171  TQWidget::focusNextPrevChild( true );
1172  break;
1173  case XEMBED_FOCUS_PREV:
1174  TQWidget::focusNextPrevChild( false );
1175  break;
1176  // L2085: The client asks for the focus.
1177  case XEMBED_REQUEST_FOCUS:
1178  if( ((QPublicWidget*)topLevelWidget())->topData()->embedded ) {
1179  focusMap->remove( topLevelWidget() );
1180  focusMap->insert( topLevelWidget(), new TQGuardedPtr<TQWidget>( this ));
1181  WId window = ((QPublicWidget*)topLevelWidget())->topData()->parentWinId;
1182  sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
1183  } else {
1184  TQFocusEvent::setReason( TQFocusEvent::Mouse );
1185  setFocus();
1186  TQFocusEvent::resetReason();
1187  }
1188  break;
1189  default:
1190  break;
1191  }
1192  }
1193  break;
1194 
1195  case ConfigureRequest:
1196  // L2090: Client wants to change its geometry.
1197  // Just inform it that nothing has changed.
1198  if (e->xconfigurerequest.window == window)
1199  {
1200  sendSyntheticConfigureNotifyEvent();
1201  }
1202  break;
1203  case MotionNotify:
1204  // fall through, workaround for Qt 3.0 < 3.0.3
1205  case EnterNotify:
1206  // L2095: See L2200.
1207  if ( TQWhatsThis::inWhatsThisMode() )
1208  enterWhatsThisMode();
1209  break;
1210  default:
1211  break;
1212  }
1213  return false;
1214 }
1215 
1216 
1217 // L2200: Try to handle Qt's "what's this" mode. Broken.
1218 // "temporary, fix in Qt (Matthias, Mon Jul 17 15:20:55 CEST 2000"
1219 void QXEmbed::enterWhatsThisMode()
1220 {
1221  // L2210: When the what-s-this pointer enters the embedded window (L2095)
1222  // cancel what-s-this mode, and use a non stantard _NET_WM_ message
1223  // to instruct the embedded client to enter the "what's this" mode.
1224  // This works only one way...
1225  TQWhatsThis::leaveWhatsThisMode();
1226  if ( !context_help )
1227  context_help = XInternAtom( x11Display(), "_NET_WM_CONTEXT_HELP", false );
1228  sendClientMessage(window , tqt_wm_protocols, context_help );
1229 }
1230 
1231 
1232 // L2300: indicates that the embedded window has been changed.
1233 void QXEmbed::windowChanged( WId )
1234 {
1235 }
1236 
1237 
1238 // L2400: Utility function for clients that embed themselves.
1239 // This is client side code.
1240 bool QXEmbed::processClientCmdline( TQWidget* client, int& argc, char ** argv )
1241 {
1242  int myargc = argc;
1243  WId window = 0;
1244  int i, j;
1245 
1246  j = 1;
1247  for ( i=1; i<myargc; i++ ) {
1248  if ( argv[i] && *argv[i] != '-' ) {
1249  argv[j++] = argv[i];
1250  continue;
1251  }
1252  TQCString arg = argv[i];
1253  if ( !strcmp(arg,"-embed") && i < myargc-1 ) {
1254  TQCString s = argv[++i];
1255  window = s.toInt();
1256  } else
1257  argv[j++] = argv[i];
1258  }
1259  argc = j;
1260 
1261  if ( window ) {
1262  embedClientIntoWindow( client, window );
1263  return true;
1264  }
1265 
1266  return false;
1267 }
1268 
1269 
1270 // L2450: Utility function for clients that embed themselves.
1271 // This is client side code.
1272 void QXEmbed::embedClientIntoWindow(TQWidget* client, WId window)
1273 {
1274  initialize();
1275  XReparentWindow(tqt_xdisplay(), client->winId(), window, 0, 0);
1276  // L2451: These two lines are redundant. See L0680.
1277  ((QXEmbed*)client)->topData()->embedded = true;
1278  ((QXEmbed*)client)->topData()->parentWinId = window;
1279  // L2452: This seems redundant because L2020 maps the window.
1280  // But calling show() might also set Qt internal flags.
1281  client->show();
1282 }
1283 
1284 
1285 
1286 // L2500: Specifies that this widget can use additional space,
1287 // and that it can survive on less than sizeHint().
1288 TQSizePolicy QXEmbed::sizePolicy() const
1289 {
1290  return TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding );
1291 }
1292 
1293 
1294 // L2520: Returns a size sufficient for the embedded window
1295 TQSize QXEmbed::sizeHint() const
1296 {
1297  return minimumSizeHint();
1298 }
1299 
1300 // L2550: Returns the minimum size specified by the embedded window.
1301 TQSize QXEmbed::minimumSizeHint() const
1302 {
1303  int minw = 0;
1304  int minh = 0;
1305  if ( window ) {
1306  XSizeHints size;
1307  long msize;
1308  if (XGetWMNormalHints(tqt_xdisplay(), window, &size, &msize)
1309  && ( size.flags & PMinSize) ) {
1310  minw = size.min_width;
1311  minh = size.min_height;
1312  }
1313  }
1314 
1315  return TQSize( minw, minh );
1316 }
1317 
1318 // L2600: Tells what shoud be done with the embedded window when
1319 // the embedding window is destroyed.
1320 void QXEmbed::setAutoDelete( bool b)
1321 {
1322  d->autoDelete = b;
1323 }
1324 
1325 // L2650: See L2600.
1326 bool QXEmbed::autoDelete() const
1327 {
1328  return d->autoDelete;
1329 }
1330 
1331 // L2700: See L2200.
1332 bool QXEmbed::customWhatsThis() const
1333 {
1334  return true;
1335 }
1336 
1337 // L2800: When using the XPLAIN protocol, this function maintains
1338 // a passive button grab when (1) the application is active
1339 // and (2) the Qt focus is not on the QXEmbed. This passive
1340 // grab intercepts button clicks in the client window and
1341 // give us chance to request the Qt focus (L2060).
1342 void QXEmbed::checkGrab()
1343 {
1344  if (d->xplain && isActiveWindow() && !hasFocus()) {
1345  if (! d->xgrab)
1346  XGrabButton(tqt_xdisplay(), AnyButton, AnyModifier, winId(),
1347  false, ButtonPressMask, GrabModeSync, GrabModeAsync,
1348  None, None );
1349  d->xgrab = true;
1350  } else {
1351  if (d->xgrab)
1352  XUngrabButton( tqt_xdisplay(), AnyButton, AnyModifier, winId() );
1353  d->xgrab = false;
1354  }
1355 }
1356 
1357 // L2900: This sends fake configure notify events to inform
1358 // the client about its window geometry. See L1390, L2024 and L2090.
1359 void QXEmbed::sendSyntheticConfigureNotifyEvent()
1360 {
1361  // L2910: It seems that the x and y coordinates are global.
1362  // But this is what ICCCM section 4.1.5 wants.
1363  // See http://lists.kde.org/?l=kfm-devel&m=107090222032378
1364  TQPoint globalPos = mapToGlobal(TQPoint(0,0));
1365  if (window) {
1366 #if 0
1367  XConfigureEvent c;
1368  memset(&c, 0, sizeof(c));
1369  c.type = ConfigureNotify;
1370  c.display = tqt_xdisplay();
1371  c.send_event = True;
1372  c.event = window;
1373  c.window = window;
1374  c.x = globalPos.x();
1375  c.y = globalPos.y();
1376  c.width = width();
1377  c.height = height();
1378  c.border_width = 0;
1379  c.above = None;
1380  c.override_redirect = 0;
1381  XSendEvent( tqt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c );
1382 #endif
1383  // Yes, this doesn't make sense at all. See the commit message.
1384  XSetWindowBorderWidth( tqt_xdisplay(), window, 1 );
1385  XSetWindowBorderWidth( tqt_xdisplay(), window, 0 );
1386  }
1387 }
1388 
1389 // L3000: One should not call TQWidget::reparent after embedding a window.
1390 void QXEmbed::reparent( TQWidget * parent, WFlags f, const TQPoint & p, bool showIt )
1391 {
1392  // TQWidget::reparent() destroys the old X Window for the widget, and
1393  // creates a new one, thus QXEmbed after reparenting is no longer the
1394  // parent of the embedded window. I think reparenting of QXEmbed can be
1395  // done only by a mistake, so just complain.
1396  Q_ASSERT( !window );
1397  TQWidget::reparent( parent, f, p, showIt );
1398 }
1399 
1400 // for KDE
1401 #include "qxembed.moc"
1402 #endif // TQ_WS_X11
KXErrorHandler
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
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
TDEStdAccel::name
TQString name(StdAccel id)

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
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeui by doxygen 1.9.1
This website is maintained by Timothy Pearson.