kwin.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org) 00003 00004 $Id: kwin.cpp 715236 2007-09-21 15:08:48Z mueller $ 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include <stdlib.h> 00023 #include <unistd.h> 00024 00025 #ifdef HAVE_SYSENT_H 00026 #include <sysent.h> 00027 #endif 00028 00029 #include <kuniqueapplication.h> 00030 #include <qbitmap.h> 00031 #include <qimage.h> 00032 #include <qwhatsthis.h> 00033 #include <qcstring.h> 00034 #include <qdialog.h> 00035 00036 #include "config.h" 00037 #include "kwin.h" 00038 #include "kapplication.h" 00039 00040 #include <kglobal.h> 00041 #include <kiconloader.h> 00042 #include <kdebug.h> 00043 00044 #include <kdatastream.h> 00045 #include <klocale.h> 00046 #include <dcopclient.h> 00047 #include <dcopref.h> 00048 #ifdef Q_WS_X11 00049 #include <kstartupinfo.h> 00050 #include <kxerrorhandler.h> 00051 00052 #include <X11/Xlib.h> 00053 #include <X11/Xatom.h> 00054 #include <X11/Xutil.h> 00055 00056 #include "netwm.h" 00057 00058 static bool atoms_created = false; 00059 extern Atom qt_wm_protocols; 00060 extern Time qt_x_time; 00061 extern Time qt_x_user_time; 00062 00063 static Atom net_wm_context_help; 00064 static Atom kde_wm_change_state; 00065 static Atom kde_wm_window_opacity; 00066 static Atom kde_wm_window_shadow; 00067 static Atom kwin_UTF8_STRING; 00068 static Atom net_wm_cm; 00069 00070 static void kwin_net_create_atoms() { 00071 if (!atoms_created){ 00072 const int max = 20; 00073 Atom* atoms[max]; 00074 const char* names[max]; 00075 Atom atoms_return[max]; 00076 int n = 0; 00077 00078 atoms[n] = &net_wm_context_help; 00079 names[n++] = "_NET_WM_CONTEXT_HELP"; 00080 00081 atoms[n] = &kde_wm_change_state; 00082 names[n++] = "_KDE_WM_CHANGE_STATE"; 00083 00084 atoms[n] = &kde_wm_window_opacity; 00085 names[n++] = (char*) "_KDE_WM_WINDOW_OPACITY"; 00086 00087 atoms[n] = &kde_wm_window_shadow; 00088 names[n++] = (char*) "_KDE_WM_WINDOW_SHADOW"; 00089 00090 char net_wm_cm_name[ 100 ]; 00091 sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( qt_xdisplay())); 00092 atoms[n] = &net_wm_cm; 00093 names[n++] = net_wm_cm_name; 00094 00095 // we need a const_cast for the shitty X API 00096 XInternAtoms( qt_xdisplay(), const_cast<char**>(names), n, false, atoms_return ); 00097 for (int i = 0; i < n; i++ ) 00098 *atoms[i] = atoms_return[i]; 00099 00100 atoms_created = True; 00101 } 00102 } 00103 #endif 00104 00105 /* 00106 Sends a client message to the ROOT window. 00107 */ 00108 #ifdef Q_WS_X11 00109 static void sendClientMessageToRoot(Window w, Atom a, long x, long y = 0, long z = 0 ){ 00110 XEvent ev; 00111 long mask; 00112 00113 memset(&ev, 0, sizeof(ev)); 00114 ev.xclient.type = ClientMessage; 00115 ev.xclient.window = w; 00116 ev.xclient.message_type = a; 00117 ev.xclient.format = 32; 00118 ev.xclient.data.l[0] = x; 00119 ev.xclient.data.l[1] = y; 00120 ev.xclient.data.l[2] = z; 00121 mask = SubstructureRedirectMask; 00122 XSendEvent(qt_xdisplay(), qt_xrootwin(), False, mask, &ev); 00123 } 00124 #endif 00125 00126 /* 00127 Send a client message to window w 00128 */ 00129 #ifdef Q_WS_X11 00130 static void sendClientMessage(Window w, Atom a, long x){ 00131 XEvent ev; 00132 long mask; 00133 00134 memset(&ev, 0, sizeof(ev)); 00135 ev.xclient.type = ClientMessage; 00136 ev.xclient.window = w; 00137 ev.xclient.message_type = a; 00138 ev.xclient.format = 32; 00139 ev.xclient.data.l[0] = x; 00140 ev.xclient.data.l[1] = CurrentTime; 00141 mask = 0L; 00142 if (w == qt_xrootwin()) 00143 mask = SubstructureRedirectMask; /* magic! */ 00144 XSendEvent(qt_xdisplay(), w, False, mask, &ev); 00145 } 00146 #endif 00147 00148 bool KWin::compositingActive() 00149 { 00150 #ifdef Q_WS_X11 00151 kwin_net_create_atoms(); 00152 return XGetSelectionOwner( qt_xdisplay(), net_wm_cm ) != None; 00153 #else 00154 return false; 00155 #endif 00156 } 00157 00158 #ifdef Q_WS_X11 00159 namespace 00160 { 00161 class ContextWidget : public QWidget 00162 { 00163 public: 00164 ContextWidget(); 00165 virtual bool x11Event( XEvent * ev); 00166 }; 00167 00168 ContextWidget::ContextWidget() 00169 : QWidget(0,0) 00170 { 00171 kwin_net_create_atoms(); 00172 kapp->installX11EventFilter( this ); 00173 QWhatsThis::enterWhatsThisMode(); 00174 QCursor c = *QApplication::overrideCursor(); 00175 QWhatsThis::leaveWhatsThisMode(); 00176 XGrabPointer( qt_xdisplay(), qt_xrootwin(), true, 00177 (uint)( ButtonPressMask | ButtonReleaseMask | 00178 PointerMotionMask | EnterWindowMask | 00179 LeaveWindowMask ), 00180 GrabModeAsync, GrabModeAsync, 00181 None, c.handle(), CurrentTime ); 00182 qApp->enter_loop(); 00183 } 00184 00185 00186 bool ContextWidget::x11Event( XEvent * ev) 00187 { 00188 if ( ev->type == ButtonPress && ev->xbutton.button == Button1 ) { 00189 XUngrabPointer( qt_xdisplay(), ev->xbutton.time ); 00190 Window root; 00191 Window child = qt_xrootwin(); 00192 int root_x, root_y, lx, ly; 00193 uint state; 00194 Window w; 00195 do { 00196 w = child; 00197 XQueryPointer( qt_xdisplay(), w, &root, &child, 00198 &root_x, &root_y, &lx, &ly, &state ); 00199 } while ( child != None && child != w ); 00200 00201 ::sendClientMessage(w, qt_wm_protocols, net_wm_context_help); 00202 XEvent e = *ev; 00203 e.xbutton.window = w; 00204 e.xbutton.subwindow = w; 00205 e.xbutton.x = lx; 00206 e.xbutton.y = ly; 00207 XSendEvent( qt_xdisplay(), w, true, ButtonPressMask, &e ); 00208 qApp->exit_loop(); 00209 return true; 00210 } 00211 return false; 00212 } 00213 } // namespace 00214 #endif 00215 00216 void KWin::invokeContextHelp() 00217 { 00218 #ifdef Q_WS_X11 00219 ContextWidget w; 00220 #endif 00221 } 00222 00223 void KWin::setSystemTrayWindowFor( WId trayWin, WId forWin ) 00224 { 00225 #ifdef Q_WS_X11 00226 NETWinInfo info( qt_xdisplay(), trayWin, qt_xrootwin(), 0 ); 00227 if ( !forWin ) 00228 forWin = qt_xrootwin(); 00229 info.setKDESystemTrayWinFor( forWin ); 00230 NETRootInfo rootinfo( qt_xdisplay(), NET::Supported ); 00231 if( !rootinfo.isSupported( NET::WMKDESystemTrayWinFor )) { 00232 DCOPRef ref( "kded", "kded" ); 00233 if( !ref.send( "loadModule", QCString( "kdetrayproxy" ))) 00234 kdWarning( 176 ) << "Loading of kdetrayproxy failed." << endl; 00235 } 00236 #endif 00237 } 00238 00239 void KWin::activateWindow( WId win, long time ) 00240 { 00241 #ifdef Q_WS_X11 00242 NETRootInfo info( qt_xdisplay(), 0 ); 00243 if( time == 0 ) 00244 time = qt_x_user_time; 00245 info.setActiveWindow( win, NET::FromApplication, time, 00246 kapp->activeWindow() ? kapp->activeWindow()->winId() : 0 ); 00247 #endif // Q_WS_X11 ... 00248 KUniqueApplication::setHandleAutoStarted(); 00249 } 00250 00251 void KWin::forceActiveWindow( WId win, long time ) 00252 { 00253 #ifdef Q_WS_X11 00254 NETRootInfo info( qt_xdisplay(), 0 ); 00255 if( time == 0 ) 00256 time = qt_x_time; 00257 info.setActiveWindow( win, NET::FromTool, time, 0 ); 00258 #endif // Q_WS_X11 00259 KUniqueApplication::setHandleAutoStarted(); 00260 } 00261 00262 void KWin::setActiveWindow( WId win ) 00263 { 00264 #ifdef Q_WS_X11 00265 NETRootInfo info( qt_xdisplay(), 0 ); 00266 info.setActiveWindow( win, NET::FromUnknown, 0, 0 ); 00267 #endif 00268 KUniqueApplication::setHandleAutoStarted(); 00269 } 00270 00271 void KWin::demandAttention( WId win, bool set ) 00272 { 00273 #ifdef Q_WS_X11 00274 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 ); 00275 info.setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention ); 00276 #endif 00277 } 00278 00279 void KWin::setUserTime( WId win, long time ) 00280 { 00281 #ifdef Q_WS_X11 00282 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 ); 00283 info.setUserTime( time ); 00284 #endif 00285 } 00286 00287 KWin::WindowInfo KWin::windowInfo( WId win, unsigned long properties, unsigned long properties2 ) 00288 { 00289 return WindowInfo( win, properties, properties2 ); 00290 } 00291 00292 00293 WId KWin::transientFor( WId win ) 00294 { 00295 #ifdef Q_WS_X11 00296 KXErrorHandler handler; // ignore badwindow 00297 Window transient_for = None; 00298 if( XGetTransientForHint( qt_xdisplay(), win, &transient_for )) 00299 return transient_for; 00300 // XGetTransientForHint() did sync 00301 return None; 00302 #else 00303 return 0L; 00304 #endif 00305 } 00306 00307 void KWin::setMainWindow( QWidget* subwindow, WId mainwindow ) 00308 { 00309 #ifdef Q_WS_X11 00310 if( mainwindow != 0 ) 00311 { 00312 /* 00313 Grmbl. See QDialog::show(). That should get fixed in Qt somehow. 00314 */ 00315 if( qt_cast< QDialog* >( subwindow ) != NULL 00316 && subwindow->parentWidget() == NULL 00317 && kapp->mainWidget() != NULL ) 00318 { 00319 kdWarning() << "KWin::setMainWindow(): There either mustn't be kapp->mainWidget()," 00320 " or the dialog must have a non-NULL parent, otherwise Qt will reset the change. Bummer." << endl; 00321 } 00322 XSetTransientForHint( qt_xdisplay(), subwindow->winId(), mainwindow ); 00323 } 00324 else 00325 XDeleteProperty( qt_xdisplay(), subwindow->winId(), XA_WM_TRANSIENT_FOR ); 00326 #endif 00327 } 00328 00329 WId KWin::groupLeader( WId win ) 00330 { 00331 #ifdef Q_WS_X11 00332 KXErrorHandler handler; // ignore badwindow 00333 XWMHints *hints = XGetWMHints( qt_xdisplay(), win ); 00334 Window window_group = None; 00335 if ( hints ) 00336 { 00337 if( hints->flags & WindowGroupHint ) 00338 window_group = hints->window_group; 00339 XFree( reinterpret_cast< char* >( hints )); 00340 } 00341 // XGetWMHints() did sync 00342 return window_group; 00343 #else 00344 return 0L; 00345 #endif 00346 } 00347 00348 // this one is deprecated, KWin::WindowInfo should be used instead 00349 KWin::Info KWin::info( WId win ) 00350 { 00351 Info w; 00352 #ifdef Q_WS_X11 00353 NETWinInfo inf( qt_xdisplay(), win, qt_xrootwin(), 00354 NET::WMState | 00355 NET::WMStrut | 00356 NET::WMWindowType | 00357 NET::WMName | 00358 NET::WMVisibleName | 00359 NET::WMDesktop | 00360 NET::WMPid | 00361 NET::WMKDEFrameStrut | 00362 NET::XAWMState 00363 ); 00364 00365 w.win = win; 00366 w.state = inf.state(); 00367 w.mappingState = inf.mappingState(); 00368 w.strut = inf.strut(); 00369 w.windowType = inf.windowType( -1U ); 00370 if ( inf.name() ) { 00371 w.name = QString::fromUtf8( inf.name() ); 00372 } else { 00373 char* c = 0; 00374 if ( XFetchName( qt_xdisplay(), win, &c ) != 0 ) { 00375 w.name = QString::fromLocal8Bit( c ); 00376 XFree( c ); 00377 } 00378 } 00379 if ( inf.visibleName() ) 00380 w.visibleName = QString::fromUtf8( inf.visibleName() ); 00381 else 00382 w.visibleName = w.name; 00383 00384 w.desktop = inf.desktop(); 00385 w.onAllDesktops = inf.desktop() == NETWinInfo::OnAllDesktops; 00386 w.pid = inf.pid(); 00387 NETRect frame, geom; 00388 inf.kdeGeometry( frame, geom ); 00389 w.geometry.setRect( geom.pos.x, geom.pos.y, geom.size.width, geom.size.height ); 00390 w.frameGeometry.setRect( frame.pos.x, frame.pos.y, frame.size.width, frame.size.height ); 00391 #endif 00392 return w; 00393 } 00394 00395 QPixmap KWin::icon( WId win, int width, int height, bool scale ) 00396 { 00397 return icon( win, width, height, scale, NETWM | WMHints | ClassHint | XApp ); 00398 } 00399 00400 00401 QPixmap KWin::icon( WId win, int width, int height, bool scale, int flags ) 00402 { 00403 #ifdef Q_WS_X11 00404 KXErrorHandler handler; // ignore badwindow 00405 #endif 00406 QPixmap result; 00407 #ifdef Q_WS_X11 00408 if( flags & NETWM ) { 00409 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMIcon ); 00410 NETIcon ni = info.icon( width, height ); 00411 if ( ni.data && ni.size.width > 0 && ni.size.height > 0 ) { 00412 QImage img( (uchar*) ni.data, (int) ni.size.width, (int) ni.size.height, 32, 0, 0, QImage::IgnoreEndian ); 00413 img.setAlphaBuffer( true ); 00414 if ( scale && width > 0 && height > 0 &&img.size() != QSize( width, height ) && !img.isNull() ) 00415 img = img.smoothScale( width, height ); 00416 if ( !img.isNull() ) 00417 result.convertFromImage( img ); 00418 return result; 00419 } 00420 } 00421 00422 if( flags & WMHints ) { 00423 Pixmap p = None; 00424 Pixmap p_mask = None; 00425 00426 XWMHints *hints = XGetWMHints(qt_xdisplay(), win ); 00427 if (hints && (hints->flags & IconPixmapHint)){ 00428 p = hints->icon_pixmap; 00429 } 00430 if (hints && (hints->flags & IconMaskHint)){ 00431 p_mask = hints->icon_mask; 00432 } 00433 if (hints) 00434 XFree((char*)hints); 00435 00436 if (p != None){ 00437 Window root; 00438 int x, y; 00439 unsigned int w = 0; 00440 unsigned int h = 0; 00441 unsigned int border_w, depth; 00442 XGetGeometry(qt_xdisplay(), p, &root, 00443 &x, &y, &w, &h, &border_w, &depth); 00444 if (w > 0 && h > 0){ 00445 QPixmap pm(w, h, depth); 00446 // Always detach before doing something behind QPixmap's back. 00447 pm.detach(); 00448 XCopyArea(qt_xdisplay(), p, pm.handle(), 00449 qt_xget_temp_gc(qt_xscreen(), depth==1), 00450 0, 0, w, h, 0, 0); 00451 if (p_mask != None){ 00452 QBitmap bm(w, h); 00453 XCopyArea(qt_xdisplay(), p_mask, bm.handle(), 00454 qt_xget_temp_gc(qt_xscreen(), true), 00455 0, 0, w, h, 0, 0); 00456 pm.setMask(bm); 00457 } 00458 if ( scale && width > 0 && height > 0 && !pm.isNull() && 00459 ( (int) w != width || (int) h != height) ){ 00460 result.convertFromImage( pm.convertToImage().smoothScale( width, height ) ); 00461 } else { 00462 result = pm; 00463 } 00464 } 00465 } 00466 } 00467 00468 // Since width can be any arbitrary size, but the icons cannot, 00469 // take the nearest value for best results (ignoring 22 pixel 00470 // icons as they don't exist for apps): 00471 int iconWidth; 00472 if( width < 24 ) 00473 iconWidth = 16; 00474 else if( width < 40 ) 00475 iconWidth = 32; 00476 else 00477 iconWidth = 48; 00478 00479 if( flags & ClassHint ) { 00480 // Try to load the icon from the classhint if the app didn't specify 00481 // its own: 00482 if( result.isNull() ) { 00483 00484 XClassHint hint; 00485 if( XGetClassHint( qt_xdisplay(), win, &hint ) ) { 00486 QString className = hint.res_class; 00487 00488 QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( className.lower(), KIcon::Small, iconWidth, 00489 KIcon::DefaultState, 0, true ); 00490 if( scale && !pm.isNull() ) 00491 result.convertFromImage( pm.convertToImage().smoothScale( width, height ) ); 00492 else 00493 result = pm; 00494 00495 XFree( hint.res_name ); 00496 XFree( hint.res_class ); 00497 } 00498 } 00499 } 00500 00501 if( flags & XApp ) { 00502 // If the icon is still a null pixmap, load the 'xapp' icon 00503 // as a last resort: 00504 if ( result.isNull() ) { 00505 QPixmap pm = KGlobal::instance()->iconLoader()->loadIcon( "xapp", KIcon::Small, iconWidth, 00506 KIcon::DefaultState, 0, true ); 00507 if( scale && !pm.isNull() ) 00508 result.convertFromImage( pm.convertToImage().smoothScale( width, height ) ); 00509 else 00510 result = pm; 00511 } 00512 } 00513 #endif 00514 return result; 00515 } 00516 00517 void KWin::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon ) 00518 { 00519 #ifdef Q_WS_X11 00520 if ( icon.isNull() ) 00521 return; 00522 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 ); 00523 QImage img = icon.convertToImage().convertDepth( 32 ); 00524 NETIcon ni; 00525 ni.size.width = img.size().width(); 00526 ni.size.height = img.size().height(); 00527 ni.data = (unsigned char *) img.bits(); 00528 info.setIcon( ni, true ); 00529 if ( miniIcon.isNull() ) 00530 return; 00531 img = miniIcon.convertToImage().convertDepth( 32 ); 00532 ni.size.width = img.size().width(); 00533 ni.size.height = img.size().height(); 00534 ni.data = (unsigned char *) img.bits(); 00535 info.setIcon( ni, false ); 00536 #endif 00537 } 00538 00539 void KWin::setType( WId win, NET::WindowType windowType ) 00540 { 00541 #ifdef Q_WS_X11 00542 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 ); 00543 info.setWindowType( windowType ); 00544 #endif 00545 } 00546 00547 void KWin::setState( WId win, unsigned long state ) 00548 { 00549 #ifdef Q_WS_X11 00550 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState ); 00551 info.setState( state, state ); 00552 #endif 00553 } 00554 00555 void KWin::clearState( WId win, unsigned long state ) 00556 { 00557 #ifdef Q_WS_X11 00558 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMState ); 00559 info.setState( 0, state ); 00560 #endif 00561 } 00562 00563 void KWin::setOpacity( WId win, uint percent ) 00564 { 00565 #ifdef Q_WS_X11 00566 kwin_net_create_atoms(); 00567 if (percent > 99) 00568 XDeleteProperty (qt_xdisplay(), win, kde_wm_window_opacity); 00569 else 00570 { 00571 long opacity = long(0xFFFFFFFF/100.0*percent); 00572 XChangeProperty(qt_xdisplay(), win, kde_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &opacity, 1L); 00573 } 00574 #endif 00575 } 00576 00577 void KWin::setShadowSize( WId win, uint percent ) 00578 { 00579 #ifdef Q_WS_X11 00580 kwin_net_create_atoms(); 00581 long shadowSize = long(0xFFFFFFFF/100.0*percent); 00582 XChangeProperty(qt_xdisplay(), win, kde_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &shadowSize, 1L); 00583 #endif 00584 } 00585 00586 void KWin::setOnAllDesktops( WId win, bool b ) 00587 { 00588 #ifdef Q_WS_X11 00589 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop ); 00590 if ( b ) 00591 info.setDesktop( NETWinInfo::OnAllDesktops ); 00592 else if ( info.desktop() == NETWinInfo::OnAllDesktops ) { 00593 NETRootInfo rinfo( qt_xdisplay(), NET::CurrentDesktop ); 00594 info.setDesktop( rinfo.currentDesktop() ); 00595 } 00596 #endif 00597 } 00598 00599 void KWin::setOnDesktop( WId win, int desktop ) 00600 { 00601 #ifdef Q_WS_X11 00602 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), NET::WMDesktop ); 00603 info.setDesktop( desktop ); 00604 #endif 00605 } 00606 00607 void KWin::setExtendedStrut( WId win, int left_width, int left_start, int left_end, 00608 int right_width, int right_start, int right_end, int top_width, int top_start, int top_end, 00609 int bottom_width, int bottom_start, int bottom_end ) 00610 { 00611 #ifdef Q_WS_X11 00612 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 ); 00613 NETExtendedStrut strut; 00614 strut.left_width = left_width; 00615 strut.right_width = right_width; 00616 strut.top_width = top_width; 00617 strut.bottom_width = bottom_width; 00618 strut.left_start = left_start; 00619 strut.left_end = left_end; 00620 strut.right_start = right_start; 00621 strut.right_end = right_end; 00622 strut.top_start = top_start; 00623 strut.top_end = top_end; 00624 strut.bottom_start = bottom_start; 00625 strut.bottom_end = bottom_end; 00626 info.setExtendedStrut( strut ); 00627 #endif 00628 } 00629 00630 void KWin::setStrut( WId win, int left, int right, int top, int bottom ) 00631 { 00632 #ifdef Q_WS_X11 00633 NETWinInfo info( qt_xdisplay(), win, qt_xrootwin(), 0 ); 00634 NETStrut strut; 00635 strut.left = left; 00636 strut.right = right; 00637 strut.top = top; 00638 strut.bottom = bottom; 00639 info.setStrut( strut ); 00640 #endif 00641 } 00642 00643 int KWin::currentDesktop() 00644 { 00645 #ifdef Q_WS_X11 00646 if (!qt_xdisplay()) 00647 #endif 00648 return 1; 00649 #ifdef Q_WS_X11 00650 NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop ); 00651 return info.currentDesktop(); 00652 #endif 00653 } 00654 00655 int KWin::numberOfDesktops() 00656 { 00657 #ifdef Q_WS_X11 00658 if (!qt_xdisplay()) 00659 #endif 00660 return 0; 00661 #ifdef Q_WS_X11 00662 NETRootInfo info( qt_xdisplay(), NET::NumberOfDesktops ); 00663 return info.numberOfDesktops(); 00664 #endif 00665 } 00666 00667 void KWin::setCurrentDesktop( int desktop ) 00668 { 00669 #ifdef Q_WS_X11 00670 NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop ); 00671 info.setCurrentDesktop( desktop ); 00672 #endif 00673 } 00674 00675 void KWin::setCurrentDesktopViewport( int desktop, QPoint viewport ) 00676 { 00677 #ifdef Q_WS_X11 00678 NETRootInfo info( qt_xdisplay(), NET::CurrentDesktop ); 00679 NETPoint netview; 00680 netview.x = viewport.x(); 00681 netview.y = viewport.y(); 00682 info.setDesktopViewport( desktop, netview ); 00683 #endif 00684 } 00685 00686 void KWin::iconifyWindow( WId win, bool animation) 00687 { 00688 #ifdef Q_WS_X11 00689 if ( !animation ) 00690 { 00691 kwin_net_create_atoms(); 00692 sendClientMessageToRoot( win, kde_wm_change_state, IconicState, 1 ); 00693 } 00694 XIconifyWindow( qt_xdisplay(), win, qt_xscreen() ); 00695 #endif 00696 } 00697 00698 00699 void KWin::deIconifyWindow( WId win, bool animation ) 00700 { 00701 #ifdef Q_WS_X11 00702 if ( !animation ) 00703 { 00704 kwin_net_create_atoms(); 00705 sendClientMessageToRoot( win, kde_wm_change_state, NormalState, 1 ); 00706 } 00707 XMapWindow( qt_xdisplay(), win ); 00708 #endif 00709 } 00710 00711 void KWin::raiseWindow( WId win ) 00712 { 00713 #ifdef Q_WS_X11 00714 NETRootInfo info( qt_xdisplay(), NET::Supported ); 00715 if( info.isSupported( NET::WM2RestackWindow )) 00716 info.restackRequest( win, None, Above ); 00717 else 00718 XRaiseWindow( qt_xdisplay(), win ); 00719 #endif 00720 } 00721 00722 void KWin::lowerWindow( WId win ) 00723 { 00724 #ifdef Q_WS_X11 00725 NETRootInfo info( qt_xdisplay(), NET::Supported ); 00726 if( info.isSupported( NET::WM2RestackWindow )) 00727 info.restackRequest( win, None, Below ); 00728 else 00729 XLowerWindow( qt_xdisplay(), win ); 00730 #endif 00731 } 00732 00733 void KWin::appStarted() 00734 { 00735 #ifdef Q_WS_X11 00736 KStartupInfo::appStarted(); 00737 #endif 00738 } 00739 00740 class KWin::WindowInfoPrivate 00741 { 00742 public: 00743 WindowInfoPrivate() 00744 #ifdef Q_WS_X11 00745 : info( NULL ) 00746 #endif 00747 {} 00748 #ifdef Q_WS_X11 00749 ~WindowInfoPrivate() { delete info; } 00750 NETWinInfo* info; 00751 #endif 00752 WId win_; 00753 QString name_; 00754 QString iconic_name_; 00755 QRect geometry_; 00756 QRect frame_geometry_; 00757 int ref; 00758 bool valid; 00759 private: 00760 WindowInfoPrivate( const WindowInfoPrivate& ); 00761 void operator=( const WindowInfoPrivate& ); 00762 }; 00763 00764 // KWin::info() should be updated too if something has to be changed here 00765 KWin::WindowInfo::WindowInfo( WId win, unsigned long properties, unsigned long properties2 ) 00766 { 00767 #ifdef Q_WS_X11 00768 KXErrorHandler handler; 00769 d = new WindowInfoPrivate; 00770 d->ref = 1; 00771 if( properties == 0 ) 00772 properties = NET::WMState | 00773 NET::WMStrut | 00774 NET::WMWindowType | 00775 NET::WMName | 00776 NET::WMVisibleName | 00777 NET::WMIconName | 00778 NET::WMVisibleIconName | 00779 NET::WMDesktop | 00780 NET::WMPid | 00781 NET::WMKDEFrameStrut | 00782 NET::XAWMState | 00783 NET::WMGeometry; 00784 if( properties & NET::WMVisibleIconName ) 00785 properties |= NET::WMIconName | NET::WMVisibleName; // force, in case it will be used as a fallback 00786 if( properties & NET::WMVisibleName ) 00787 properties |= NET::WMName; // force, in case it will be used as a fallback 00788 if( properties2 & NET::WM2ExtendedStrut ) 00789 properties |= NET::WMStrut; // will be used as fallback 00790 properties |= NET::XAWMState; // force to get error detection for valid() 00791 unsigned long props[ 2 ] = { properties, properties2 }; 00792 d->info = new NETWinInfo( qt_xdisplay(), win, qt_xrootwin(), props, 2 ); 00793 d->win_ = win; 00794 if( properties & NET::WMName ) { 00795 if( d->info->name() && d->info->name()[ 0 ] != '\0' ) 00796 d->name_ = QString::fromUtf8( d->info->name() ); 00797 else 00798 d->name_ = readNameProperty( win, XA_WM_NAME ); 00799 } 00800 if( properties & NET::WMIconName ) { 00801 if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' ) 00802 d->iconic_name_ = QString::fromUtf8( d->info->iconName()); 00803 else 00804 d->iconic_name_ = readNameProperty( win, XA_WM_ICON_NAME ); 00805 } 00806 if( properties & ( NET::WMGeometry | NET::WMKDEFrameStrut )) { 00807 NETRect frame, geom; 00808 d->info->kdeGeometry( frame, geom ); 00809 d->geometry_.setRect( geom.pos.x, geom.pos.y, geom.size.width, geom.size.height ); 00810 d->frame_geometry_.setRect( frame.pos.x, frame.pos.y, frame.size.width, frame.size.height ); 00811 } 00812 d->valid = !handler.error( false ); // no sync - NETWinInfo did roundtrips 00813 #endif 00814 } 00815 00816 // this one is only to make QValueList<> or similar happy 00817 KWin::WindowInfo::WindowInfo() 00818 : d( NULL ) 00819 { 00820 } 00821 00822 KWin::WindowInfo::~WindowInfo() 00823 { 00824 if( d != NULL ) { 00825 if( --d->ref == 0 ) { 00826 delete d; 00827 } 00828 } 00829 } 00830 00831 KWin::WindowInfo::WindowInfo( const WindowInfo& wininfo ) 00832 : d( wininfo.d ) 00833 { 00834 if( d != NULL ) 00835 ++d->ref; 00836 } 00837 00838 KWin::WindowInfo& KWin::WindowInfo::operator=( const WindowInfo& wininfo ) 00839 { 00840 if( d != wininfo.d ) { 00841 if( d != NULL ) 00842 if( --d->ref == 0 ) 00843 delete d; 00844 d = wininfo.d; 00845 if( d != NULL ) 00846 ++d->ref; 00847 } 00848 return *this; 00849 } 00850 00851 bool KWin::WindowInfo::valid( bool withdrawn_is_valid ) const 00852 { 00853 if( !d->valid ) 00854 return false; 00855 if( !withdrawn_is_valid && mappingState() == NET::Withdrawn ) 00856 return false; 00857 return true; 00858 } 00859 00860 WId KWin::WindowInfo::win() const 00861 { 00862 return d->win_; 00863 } 00864 00865 unsigned long KWin::WindowInfo::state() const 00866 { 00867 #ifdef Q_WS_X11 00868 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMState ) == 0, 176 ) 00869 << "Pass NET::WMState to KWin::windowInfo()" << endl; 00870 return d->info->state(); 00871 #else 00872 return 0; 00873 #endif 00874 } 00875 00876 NET::MappingState KWin::WindowInfo::mappingState() const 00877 { 00878 #ifdef Q_WS_X11 00879 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::XAWMState ) == 0, 176 ) 00880 << "Pass NET::XAWMState to KWin::windowInfo()" << endl; 00881 return d->info->mappingState(); 00882 #else 00883 return NET::Visible; 00884 #endif 00885 } 00886 00887 NETExtendedStrut KWin::WindowInfo::extendedStrut() const 00888 { 00889 #ifdef Q_WS_X11 00890 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ExtendedStrut ) == 0, 176 ) 00891 << "Pass NET::WM2ExtendedStrut to second argument of KWin::windowInfo()" << endl; 00892 NETExtendedStrut ext = d->info->extendedStrut(); 00893 NETStrut str = d->info->strut(); 00894 if( ext.left_width == 0 && ext.right_width == 0 && ext.top_width == 0 && ext.bottom_width == 0 00895 && ( str.left != 0 || str.right != 0 || str.top != 0 || str.bottom != 0 )) { 00896 // build extended from simple 00897 if( str.left != 0 ) { 00898 ext.left_width = str.left; 00899 ext.left_start = 0; 00900 ext.left_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay())); 00901 } 00902 if( str.right != 0 ) { 00903 ext.right_width = str.right; 00904 ext.right_start = 0; 00905 ext.right_end = XDisplayHeight( qt_xdisplay(), DefaultScreen( qt_xdisplay())); 00906 } 00907 if( str.top != 0 ) { 00908 ext.top_width = str.top; 00909 ext.top_start = 0; 00910 ext.top_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay())); 00911 } 00912 if( str.bottom != 0 ) { 00913 ext.bottom_width = str.bottom; 00914 ext.bottom_start = 0; 00915 ext.bottom_end = XDisplayWidth( qt_xdisplay(), DefaultScreen( qt_xdisplay())); 00916 } 00917 } 00918 return ext; 00919 #else 00920 NETExtendedStrut n; 00921 return n; 00922 #endif 00923 } 00924 00925 NETStrut KWin::WindowInfo::strut() const 00926 { 00927 #ifdef Q_WS_X11 00928 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMStrut ) == 0, 176 ) 00929 << "Pass NET::WMStrut to KWin::windowInfo()" << endl; 00930 return d->info->strut(); 00931 #else 00932 NETStrut n; 00933 return n; 00934 #endif 00935 } 00936 00937 NET::WindowType KWin::WindowInfo::windowType( int supported_types ) const 00938 { 00939 #ifdef Q_WS_X11 00940 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMWindowType ) == 0, 176 ) 00941 << "Pass NET::WMWindowType to KWin::windowInfo()" << endl; 00942 return d->info->windowType( supported_types ); 00943 #else 00944 return 0; 00945 #endif 00946 } 00947 00948 QString KWin::WindowInfo::visibleNameWithState() const 00949 { 00950 QString s = visibleName(); 00951 if ( isMinimized() ) { 00952 s.prepend('('); 00953 s.append(')'); 00954 } 00955 return s; 00956 } 00957 00958 QString KWin::Info::visibleNameWithState() const 00959 { 00960 QString s = visibleName; 00961 if ( isMinimized() ) { 00962 s.prepend('('); 00963 s.append(')'); 00964 } 00965 return s; 00966 } 00967 00968 QString KWin::WindowInfo::visibleName() const 00969 { 00970 #ifdef Q_WS_X11 00971 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMVisibleName ) == 0, 176 ) 00972 << "Pass NET::WMVisibleName to KWin::windowInfo()" << endl; 00973 return d->info->visibleName() && d->info->visibleName()[ 0 ] != '\0' 00974 ? QString::fromUtf8(d->info->visibleName()) : name(); 00975 #else 00976 return QString("name"); 00977 #endif 00978 } 00979 00980 QString KWin::WindowInfo::name() const 00981 { 00982 #ifdef Q_WS_X11 00983 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMName ) == 0, 176 ) 00984 << "Pass NET::WMName to KWin::windowInfo()" << endl; 00985 return d->name_; 00986 #else 00987 return QString(); 00988 #endif 00989 } 00990 00991 QString KWin::WindowInfo::visibleIconNameWithState() const 00992 { 00993 QString s = visibleIconName(); 00994 if ( isMinimized() ) { 00995 s.prepend('('); 00996 s.append(')'); 00997 } 00998 return s; 00999 } 01000 01001 QString KWin::WindowInfo::visibleIconName() const 01002 { 01003 #ifdef Q_WS_X11 01004 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMVisibleIconName ) == 0, 176 ) 01005 << "Pass NET::WMVisibleIconName to KWin::windowInfo()" << endl; 01006 if( d->info->visibleIconName() && d->info->visibleIconName()[ 0 ] != '\0' ) 01007 return QString::fromUtf8( d->info->visibleIconName()); 01008 if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' ) 01009 return QString::fromUtf8( d->info->iconName()); 01010 if( !d->iconic_name_.isEmpty()) 01011 return d->iconic_name_; 01012 #endif 01013 return visibleName(); 01014 } 01015 01016 QString KWin::WindowInfo::iconName() const 01017 { 01018 #ifdef Q_WS_X11 01019 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMIconName ) == 0, 176 ) 01020 << "Pass NET::WMIconName to KWin::windowInfo()" << endl; 01021 if( d->info->iconName() && d->info->iconName()[ 0 ] != '\0' ) 01022 return QString::fromUtf8( d->info->iconName()); 01023 if( !d->iconic_name_.isEmpty()) 01024 return d->iconic_name_; 01025 #endif 01026 return name(); 01027 } 01028 01029 bool KWin::WindowInfo::isOnCurrentDesktop() const 01030 { 01031 #ifdef Q_WS_X11 01032 return isOnDesktop( KWin::currentDesktop()); 01033 #else 01034 return false; 01035 #endif 01036 } 01037 01038 bool KWin::WindowInfo::isOnDesktop( int desktop ) const 01039 { 01040 #ifdef Q_WS_X11 01041 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 ) 01042 << "Pass NET::WMDesktop to KWin::windowInfo()" << endl; 01043 return d->info->desktop() == desktop || d->info->desktop() == NET::OnAllDesktops; 01044 #else 01045 return false; 01046 #endif 01047 } 01048 01049 bool KWin::WindowInfo::onAllDesktops() const 01050 { 01051 #ifdef Q_WS_X11 01052 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 ) 01053 << "Pass NET::WMDesktop to KWin::windowInfo()" << endl; 01054 return d->info->desktop() == NET::OnAllDesktops; 01055 #else 01056 return false; 01057 #endif 01058 } 01059 01060 int KWin::WindowInfo::desktop() const 01061 { 01062 #ifdef Q_WS_X11 01063 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMDesktop ) == 0, 176 ) 01064 << "Pass NET::WMDesktop to KWin::windowInfo()" << endl; 01065 return d->info->desktop(); 01066 #else 01067 return 1; 01068 #endif 01069 } 01070 01071 QRect KWin::WindowInfo::geometry() const 01072 { 01073 #ifdef Q_WS_X11 01074 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMGeometry ) == 0, 176 ) 01075 << "Pass NET::WMGeometry to KWin::windowInfo()" << endl; 01076 return d->geometry_; 01077 #else 01078 return QRect( 100, 100, 200, 200 ); 01079 #endif 01080 } 01081 01082 QRect KWin::WindowInfo::frameGeometry() const 01083 { 01084 #ifdef Q_WS_X11 01085 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS ] & NET::WMKDEFrameStrut ) == 0, 176 ) 01086 << "Pass NET::WMKDEFrameStrut to KWin::windowInfo()" << endl; 01087 return d->frame_geometry_; 01088 #else 01089 return QRect(); 01090 #endif 01091 } 01092 01093 WId KWin::WindowInfo::transientFor() const 01094 { 01095 #ifdef Q_WS_X11 01096 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2TransientFor ) == 0, 176 ) 01097 << "Pass NET::WM2TransientFor to KWin::windowInfo()" << endl; 01098 return d->info->transientFor(); 01099 #else 01100 return 0; 01101 #endif 01102 } 01103 01104 WId KWin::WindowInfo::groupLeader() const 01105 { 01106 #ifdef Q_WS_X11 01107 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2GroupLeader ) == 0, 176 ) 01108 << "Pass NET::WM2GroupLeader to KWin::windowInfo()" << endl; 01109 return d->info->groupLeader(); 01110 #else 01111 return 0; 01112 #endif 01113 } 01114 01115 QCString KWin::WindowInfo::windowClassClass() const 01116 { 01117 #ifdef Q_WS_X11 01118 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 ) 01119 << "Pass NET::WM2WindowClass to KWin::windowInfo()" << endl; 01120 return d->info->windowClassClass(); 01121 #else 01122 return 0; 01123 #endif 01124 } 01125 01126 QCString KWin::WindowInfo::windowClassName() const 01127 { 01128 #ifdef Q_WS_X11 01129 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowClass ) == 0, 176 ) 01130 << "Pass NET::WM2WindowClass to KWin::windowInfo()" << endl; 01131 return d->info->windowClassName(); 01132 #else 01133 return 0; 01134 #endif 01135 } 01136 01137 QCString KWin::WindowInfo::windowRole() const 01138 { 01139 #ifdef Q_WS_X11 01140 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2WindowRole ) == 0, 176 ) 01141 << "Pass NET::WM2WindowRole to KWin::windowInfo()" << endl; 01142 return d->info->windowRole(); 01143 #else 01144 return 0; 01145 #endif 01146 } 01147 01148 QCString KWin::WindowInfo::clientMachine() const 01149 { 01150 #ifdef Q_WS_X11 01151 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2ClientMachine ) == 0, 176 ) 01152 << "Pass NET::WM2ClientMachine to KWin::windowInfo()" << endl; 01153 return d->info->clientMachine(); 01154 #else 01155 return 0; 01156 #endif 01157 } 01158 01159 bool KWin::WindowInfo::actionSupported( NET::Action action ) const 01160 { 01161 #ifdef Q_WS_X11 01162 kdWarning(( d->info->passedProperties()[ NETWinInfo::PROTOCOLS2 ] & NET::WM2AllowedActions ) == 0, 176 ) 01163 << "Pass NET::WM2AllowedActions to KWin::windowInfo()" << endl; 01164 if( allowedActionsSupported()) 01165 return d->info->allowedActions() & action; 01166 else 01167 #endif 01168 return true; // no idea if it's supported or not -> pretend it is 01169 } 01170 01171 // see NETWM spec section 7.6 01172 bool KWin::WindowInfo::isMinimized() const 01173 { 01174 #ifdef Q_WS_X11 01175 if( mappingState() != NET::Iconic ) 01176 return false; 01177 // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows 01178 if(( state() & NET::Hidden ) != 0 01179 && ( state() & NET::Shaded ) == 0 ) // shaded may have NET::Hidden too 01180 return true; 01181 // older WMs use WithdrawnState for other virtual desktops 01182 // and IconicState only for minimized 01183 return icccmCompliantMappingState() ? false : true; 01184 #else 01185 return false; 01186 #endif 01187 } 01188 01189 bool KWin::Info::isMinimized() const 01190 { 01191 #ifdef Q_WS_X11 01192 if( mappingState != NET::Iconic ) 01193 return false; 01194 // NETWM 1.2 compliant WM - uses NET::Hidden for minimized windows 01195 if(( state & NET::Hidden ) != 0 01196 && ( state & NET::Shaded ) == 0 ) // shaded may have NET::Hidden too 01197 return true; 01198 // older WMs use WithdrawnState for other virtual desktops 01199 // and IconicState only for minimized 01200 return icccmCompliantMappingState() ? false : true; 01201 #else 01202 return false; 01203 #endif 01204 } 01205 01206 bool KWin::Info::isIconified() const 01207 { 01208 return isMinimized(); 01209 } 01210 01211 bool KWin::icccmCompliantMappingState() 01212 { 01213 #ifdef Q_WS_X11 01214 static enum { noidea, yes, no } wm_is_1_2_compliant = noidea; 01215 if( wm_is_1_2_compliant == noidea ) { 01216 NETRootInfo info( qt_xdisplay(), NET::Supported ); 01217 wm_is_1_2_compliant = info.isSupported( NET::Hidden ) ? yes : no; 01218 } 01219 return wm_is_1_2_compliant == yes; 01220 #else 01221 return false; 01222 #endif 01223 } 01224 01225 bool KWin::allowedActionsSupported() 01226 { 01227 #ifdef Q_WS_X11 01228 static enum { noidea, yes, no } wm_supports_allowed_actions = noidea; 01229 if( wm_supports_allowed_actions == noidea ) { 01230 NETRootInfo info( qt_xdisplay(), NET::Supported ); 01231 wm_supports_allowed_actions = info.isSupported( NET::WM2AllowedActions ) ? yes : no; 01232 } 01233 return wm_supports_allowed_actions == yes; 01234 #else 01235 return false; 01236 #endif 01237 } 01238 01239 QString KWin::readNameProperty( WId win, unsigned long atom ) 01240 { 01241 #ifdef Q_WS_X11 01242 XTextProperty tp; 01243 char **text = NULL; 01244 int count; 01245 #endif 01246 QString result; 01247 #ifdef Q_WS_X11 01248 if ( XGetTextProperty( qt_xdisplay(), win, &tp, atom ) != 0 && tp.value != NULL ) 01249 { 01250 if (!kwin_UTF8_STRING) 01251 kwin_UTF8_STRING = XInternAtom( qt_xdisplay(), "UTF8_STRING", False); 01252 01253 if ( tp.encoding == kwin_UTF8_STRING ) { 01254 result = QString::fromUtf8 ( (const char*) tp.value ); 01255 } 01256 else if ( XmbTextPropertyToTextList( qt_xdisplay(), &tp, &text, &count) == Success && 01257 text != NULL && count > 0 ) { 01258 result = QString::fromLocal8Bit( text[0] ); 01259 } else if ( tp.encoding == XA_STRING ) 01260 result = QString::fromLocal8Bit( (const char*) tp.value ); 01261 if( text != NULL ) 01262 XFreeStringList( text ); 01263 XFree( tp.value ); 01264 } 01265 #endif 01266 return result; 01267 } 01268 01269 //#endif