00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "kwindowsystem.h"
00023 #include "kwindowinfo_mac_p.h"
00024
00025 #include <kiconloader.h>
00026 #include <klocale.h>
00027 #include <kuniqueapplication.h>
00028 #include <kxerrorhandler.h>
00029 #include <QtGui/QBitmap>
00030 #include <QDesktopWidget>
00031 #include <QtGui/QDialog>
00032 #include <QtDBus/QtDBus>
00033 #include <kdebug.h>
00034
00035 #include <Carbon/Carbon.h>
00036
00037
00038
00039
00040
00041
00042
00043 static bool operator<(const ProcessSerialNumber& a, const ProcessSerialNumber& b)
00044 {
00045 if (a.lowLongOfPSN != b.lowLongOfPSN) return a.lowLongOfPSN < b.lowLongOfPSN;
00046 return a.highLongOfPSN < b.highLongOfPSN;
00047 }
00048
00049 class KWindowSystemPrivate : QObject
00050 {
00051 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00052 Q_OBJECT
00053 #endif
00054 public:
00055 KWindowSystemPrivate();
00056
00057 QMap<WId, KWindowInfo> windows;
00058 QList<WId> winids;
00059 QMap<pid_t, AXObserverRef> newWindowObservers;
00060 QMap<pid_t, AXObserverRef> windowClosedObservers;
00061 QMap<ProcessSerialNumber, WId> processes;
00062 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00063 QList<KWindowInfo> nonProcessedWindows;
00064 #endif
00065
00066 EventTargetRef m_eventTarget;
00067 EventHandlerUPP m_eventHandler;
00068 EventTypeSpec m_eventType[2];
00069 EventHandlerRef m_curHandler;
00070
00071 void applicationLaunched(const ProcessSerialNumber& psn);
00072 void applicationTerminated(const ProcessSerialNumber& psn);
00073
00074 bool m_noEmit;
00075 bool waitingForTimer;
00076
00077 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00078 void newWindow(AXUIElementRef element, void* windowInfoPrivate);
00079 void windowClosed(AXUIElementRef element, void* windowInfoPrivate);
00080 #endif
00081
00082 static KWindowSystemPrivate* self() { return KWindowSystem::s_d_func(); }
00083 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00084 public slots:
00085 void tryRegisterProcess();
00086 #endif
00087 };
00088
00089 class KWindowSystemStaticContainer {
00090 public:
00091 KWindowSystemStaticContainer() : d (new KWindowSystemPrivate) { }
00092 KWindowSystem kwm;
00093 KWindowSystemPrivate* d;
00094 };
00095
00096 K_GLOBAL_STATIC(KWindowSystemStaticContainer, g_kwmInstanceContainer)
00097
00098 static OSStatus applicationEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void * inUserData)
00099 {
00100 KWindowSystemPrivate* d = (KWindowSystemPrivate*) inUserData;
00101
00102 UInt32 kind;
00103
00104 kind = GetEventKind(inEvent);
00105 ProcessSerialNumber psn;
00106 if (GetEventParameter(inEvent, kEventParamProcessID, typeProcessSerialNumber, NULL, sizeof psn, NULL, &psn) != noErr) {
00107 kWarning() << "Error getting event parameter in application event";
00108 return eventNotHandledErr;
00109 }
00110
00111 if (kind == kEventAppLaunched) {
00112 d->applicationLaunched(psn);
00113 } else if (kind == kEventAppTerminated) {
00114 d->applicationTerminated(psn);
00115 }
00116
00117 return noErr;
00118 }
00119
00120 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00121 static void windowClosedObserver(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void* refcon)
00122 {
00123 KWindowSystemPrivate::self()->windowClosed(element, refcon);
00124 }
00125
00126 static void newWindowObserver(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void* refcon)
00127 {
00128 KWindowSystemPrivate::self()->newWindow(element, refcon);
00129 }
00130 #endif
00131
00132 KWindowSystemPrivate::KWindowSystemPrivate()
00133 : QObject(0), m_noEmit(true), waitingForTimer(false)
00134 {
00135
00136 ProcessSerialNumber psn = {0, kNoProcess};
00137 while (GetNextProcess(&psn) == noErr) {
00138 kDebug(240) << "calling appLaunched for " << psn.lowLongOfPSN << ":" << psn.highLongOfPSN;
00139 applicationLaunched(psn);
00140 }
00141
00142 m_noEmit = false;
00143
00144 #ifdef Q_OS_MAC32
00145
00146 m_eventTarget = GetApplicationEventTarget();
00147 m_eventHandler = NewEventHandlerUPP(applicationEventHandler);
00148 m_eventType[0].eventClass = kEventClassApplication;
00149 m_eventType[0].eventKind = kEventAppLaunched;
00150 m_eventType[1].eventClass = kEventClassApplication;
00151 m_eventType[1].eventKind = kEventAppTerminated;
00152 if (InstallEventHandler(m_eventTarget, m_eventHandler, 2, m_eventType, this, &m_curHandler) != noErr) {
00153 kDebug(240) << "Installing event handler failed!\n";
00154 }
00155 #else
00156 #warning port me to Mac64
00157 #endif
00158 }
00159
00160 void KWindowSystemPrivate::applicationLaunched(const ProcessSerialNumber& psn) {
00161 #ifdef Q_OS_MAC32
00162 kDebug(240) << "new app: " << psn.lowLongOfPSN << ":" << psn.highLongOfPSN;
00163 ProcessInfoRec pinfo;
00164 FSSpec appSpec;
00165 pinfo.processInfoLength = sizeof pinfo;
00166 pinfo.processName = 0;
00167 pinfo.processAppSpec = &appSpec;
00168 GetProcessInformation(&psn, &pinfo);
00169 if ((pinfo.processMode & modeOnlyBackground) != 0) return;
00170
00171
00172 KWindowInfo winfo(0, 0);
00173 windows[winfo.win()] = winfo;
00174 winids.append(winfo.win());
00175 winfo.d->setProcessSerialNumber(psn);
00176 pid_t pid = winfo.d->pid();
00177 processes[psn] = winfo.win();
00178 kDebug(240) << " pid:" << pid;
00179 AXUIElementRef app = AXUIElementCreateApplication(pid);
00180 winfo.d->setAxElement(app);
00181 if (!m_noEmit) emit KWindowSystem::self()->windowAdded(winfo.win());
00182
00183 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00184
00185 AXObserverRef observer, newObserver;
00186 OSStatus err;
00187 if (AXObserverCreate(pid, windowClosedObserver, &observer) == noErr) {
00188 CFRunLoopAddSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(observer), kCFRunLoopCommonModes);
00189 windowClosedObservers[pid] = observer;
00190 }
00191 if ((err = AXObserverCreate(pid, newWindowObserver, &newObserver)) == noErr) {
00192 CFRunLoopAddSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(newObserver), kCFRunLoopCommonModes);
00193 newWindowObservers[pid] = newObserver;
00194 if ((err = AXObserverAddNotification(newObserver, app, kAXWindowCreatedNotification, winfo.d)) != noErr) {
00195 kDebug(240) << "Error " << err << " adding notification to observer";
00196
00197
00198 QTimer::singleShot(500, this, SLOT(tryRegisterProcess()));
00199 nonProcessedWindows.append(winfo);
00200 return;
00201 } else
00202 kDebug(240) << "Added notification and observer";
00203 } else {
00204 kDebug(240) << "Error creating observer";
00205 }
00206
00207
00208 CFIndex windowsInApp;
00209 AXUIElementGetAttributeValueCount(app, kAXWindowsAttribute, &windowsInApp);
00210 CFArrayRef array;
00211 AXUIElementCopyAttributeValue(app, kAXWindowsAttribute, (CFTypeRef*)&array);
00212 for (CFIndex j = 0; j < windowsInApp; j++) {
00213 AXUIElementRef win = (AXUIElementRef) CFArrayGetValueAtIndex(array, j);
00214 newWindow(win, winfo.d);
00215 }
00216 #endif
00217 #else
00218 #warning Port me to Mac64
00219 #endif
00220 }
00221
00222 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00223 void KWindowSystemPrivate::tryRegisterProcess()
00224 {
00225 kDebug(240) << "Single-shot timer, trying to register processes";
00226 while (!nonProcessedWindows.empty()) {
00227 KWindowInfo winfo = nonProcessedWindows.takeLast();
00228 pid_t pid = winfo.d->pid();
00229 AXUIElementRef app = winfo.d->axElement();
00230 ProcessSerialNumber psn = winfo.d->psn();
00231
00232
00233 AXObserverRef observer;
00234 OSStatus err;
00235 observer = newWindowObservers[pid];
00236 if ((err = AXObserverAddNotification(observer, app, kAXWindowCreatedNotification, winfo.d)) != noErr) {
00237 kDebug(240) << "Error " << err << " adding notification to observer";
00238 } else
00239 kDebug(240) << "Added notification and observer";
00240
00241 observer = windowClosedObservers[pid];
00242
00243 CFIndex windowsInApp;
00244 AXUIElementGetAttributeValueCount(app, kAXWindowsAttribute, &windowsInApp);
00245 CFArrayRef array;
00246 AXUIElementCopyAttributeValue(app, kAXWindowsAttribute, (CFTypeRef*)&array);
00247 for (CFIndex j = 0; j < windowsInApp; j++) {
00248 AXUIElementRef win = (AXUIElementRef) CFArrayGetValueAtIndex(array, j);
00249 newWindow(win, winfo.d);
00250 }
00251 }
00252 }
00253 #endif
00254
00255 void KWindowSystemPrivate::applicationTerminated(const ProcessSerialNumber& psn)
00256 {
00257 kDebug(240) << "Terminated PSN: " << psn.lowLongOfPSN << ":" << psn.highLongOfPSN;
00258 WId id = processes[psn];
00259 if (windows.contains(id)) {
00260 KWindowInfo winfo = windows[id];
00261 foreach (KWindowInfo::Private* wi, winfo.d->children) {
00262 winids.removeAll(wi->win);
00263 emit KWindowSystem::self()->windowRemoved(wi->win);
00264 }
00265 winids.removeAll(id);
00266 emit KWindowSystem::self()->windowRemoved(winfo.win());
00267 }
00268 }
00269
00270 #ifdef EXPERIMENTAL_WINDOW_TRACKING
00271 void KWindowSystemPrivate::windowClosed(AXUIElementRef element, void* refcon)
00272 {
00273 kDebug(240) << "Received window closed notification";
00274
00275 KWindowInfo::Private* wind = (KWindowInfo::Private*) refcon;
00276 KWindowInfo::Private* parent = wind->parent;
00277 parent->children.removeAll(wind);
00278 winids.removeAll(wind->win);
00279 if (!m_noEmit) emit KWindowSystem::self()->windowRemoved(wind->win);
00280 }
00281
00282 void KWindowSystemPrivate::newWindow(AXUIElementRef win, void* refcon)
00283 {
00284 kDebug(240) << "Received new window notification";
00285
00286 KWindowInfo::Private* winfod = (KWindowInfo::Private*) refcon;
00287 pid_t pid = winfod->pid();
00288 ProcessSerialNumber psn = winfod->psn();
00289 AXObserverRef observer = windowClosedObservers[pid];
00290
00291 KWindowInfo win2(0, 0);
00292
00293 if (AXObserverAddNotification(observer, win, kAXUIElementDestroyedNotification, win2.d) != noErr) {
00294
00295 kDebug(240) "error adding closed observer to window.";
00296 return;
00297 }
00298
00299 windows[win2.win()] = win2;
00300 winids.append(win2.win());
00301 win2.d->setProcessSerialNumber(psn);
00302 win2.d->setAxElement(win);
00303 winfod->children.append(win2.d);
00304 win2.d->parent = winfod;
00305 if (!m_noEmit) emit KWindowSystem::self()->windowAdded(win2.win());
00306 }
00307 #endif
00308
00309 KWindowSystem* KWindowSystem::self()
00310 {
00311 return &(g_kwmInstanceContainer->kwm);
00312 }
00313
00314 KWindowSystemPrivate* KWindowSystem::s_d_func()
00315 {
00316 return g_kwmInstanceContainer->d;
00317 }
00318
00319 const QList<WId>& KWindowSystem::windows()
00320 {
00321 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00322 return d->winids;
00323 }
00324
00325 bool KWindowSystem::hasWId(WId id)
00326 {
00327 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00328 return d->windows.contains(id);
00329 }
00330
00331 KWindowInfo KWindowSystem::windowInfo( WId win, unsigned long properties, unsigned long properties2 )
00332 {
00333 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00334 if (d->windows.contains(win)) {
00335 return d->windows[win];
00336 } else {
00337 return KWindowInfo( win, properties, properties2 );
00338 }
00339 }
00340
00341 QList<WId> KWindowSystem::stackingOrder()
00342 {
00343
00344 QList<WId> lst;
00345 kDebug(240) << "QList<WId> KWindowSystem::stackingOrder() isn't yet implemented!";
00346 return lst;
00347 }
00348
00349 WId KWindowSystem::activeWindow()
00350 {
00351
00352 kDebug(240) << "WId KWindowSystem::activeWindow() isn't yet implemented!";
00353 return 0;
00354 }
00355
00356 void KWindowSystem::activateWindow( WId win, long time )
00357 {
00358
00359 kDebug(240) << "KWindowSystem::activateWindow( WId win, long time )isn't yet implemented!";
00360 KWindowSystemPrivate *d = KWindowSystem::s_d_func();
00361 if (d->windows.contains(win)) {
00362 ProcessSerialNumber psn = d->windows[win].d->psn();
00363 SetFrontProcess(&psn);
00364 }
00365 }
00366
00367 void KWindowSystem::forceActiveWindow( WId win, long time )
00368 {
00369
00370 kDebug(240) << "KWindowSystem::forceActiveWindow( WId win, long time ) isn't yet implemented!";
00371 activateWindow(win, time);
00372 }
00373
00374 void KWindowSystem::demandAttention( WId win, bool set )
00375 {
00376
00377 kDebug(240) << "KWindowSystem::demandAttention( WId win, bool set ) isn't yet implemented!";
00378 }
00379
00380 bool KWindowSystem::compositingActive()
00381 {
00382 return true;
00383 }
00384
00385 int KWindowSystem::currentDesktop()
00386 {
00387 return 1;
00388 }
00389
00390 int KWindowSystem::numberOfDesktops()
00391 {
00392 return 1;
00393 }
00394
00395 void KWindowSystem::setCurrentDesktop( int desktop )
00396 {
00397 kDebug(240) << "KWindowSystem::setCurrentDesktop( int desktop ) isn't yet implemented!";
00398
00399 }
00400
00401 void KWindowSystem::setOnAllDesktops( WId win, bool b )
00402 {
00403 kDebug(240) << "KWindowSystem::setOnAllDesktops( WId win, bool b ) isn't yet implemented!";
00404
00405 }
00406
00407 void KWindowSystem::setOnDesktop( WId win, int desktop )
00408 {
00409
00410 kDebug(240) << "KWindowSystem::setOnDesktop( WId win, int desktop ) isn't yet implemented!";
00411 }
00412
00413 void KWindowSystem::setMainWindow( QWidget* subwindow, WId id )
00414 {
00415 kDebug(240) << "KWindowSystem::setMainWindow( QWidget*, WId ) isn't yet implemented!";
00416
00417 }
00418
00419 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale )
00420 {
00421 if (hasWId(win)) {
00422 KWindowInfo info = windowInfo(win, 0);
00423 if (!info.d->loadedData) {
00424 info.d->updateData();
00425 }
00426 IconRef icon;
00427 SInt16 label;
00428 #ifdef Q_OS_MAC32
00429 OSErr err = GetIconRefFromFile(&info.d->iconSpec, &icon, &label);
00430 #else
00431 OSStatus err = GetIconRefFromFileInfo(&info.d->iconSpec, 0, 0,
00432 kIconServicesCatalogInfoMask, 0, kIconServicesNormalUsageFlag, &icon, &label);
00433 #endif
00434 if (err != noErr) {
00435 kDebug(240) << "Error getting icon from application";
00436 return QPixmap();
00437 } else {
00438 QPixmap ret(width, height);
00439 ret.fill(QColor(0, 0, 0, 0));
00440
00441 CGRect rect = CGRectMake(0, 0, width, height);
00442
00443 CGContextRef ctx = qt_mac_cg_context(&ret);
00444 CGAffineTransform old_xform = CGContextGetCTM(ctx);
00445 CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform));
00446 CGContextConcatCTM(ctx, CGAffineTransformIdentity);
00447
00448 ::RGBColor b;
00449 b.blue = b.green = b.red = 255*255;
00450 PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon);
00451 CGContextRelease(ctx);
00452
00453 ReleaseIconRef(icon);
00454 return ret;
00455 }
00456 } else {
00457 kDebug(240) << "QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale ) isn't yet implemented for local windows!";
00458 return QPixmap();
00459 }
00460 }
00461
00462 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale, int flags )
00463 {
00464 return icon(win, width, height, scale);
00465
00466 }
00467
00468 void KWindowSystem::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
00469 {
00470
00471 kDebug(240) << "KWindowSystem::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon ) isn't yet implemented!";
00472 }
00473
00474 void KWindowSystem::setType( WId winid, NET::WindowType windowType )
00475 {
00476 #ifdef Q_OS_MAC32
00477
00478 if (hasWId(winid)) return;
00479
00480 static WindowGroupRef desktopGroup = 0;
00481 static WindowGroupRef dockGroup = 0;
00482
00483 WindowRef win = HIViewGetWindow( (HIViewRef) winid );
00484
00485 if (windowType != NET::Desktop && windowType != NET::Dock) {
00486 kDebug(240) << "setType( WId win, NET::WindowType windowType ) isn't yet implemented for the type you requested!";
00487 }
00488 if (windowType == NET::Desktop) {
00489 if (!desktopGroup) {
00490 CreateWindowGroup(0, &desktopGroup);
00491 SetWindowGroupLevel(desktopGroup, kCGDesktopIconWindowLevel);
00492 }
00493 SetWindowGroup(win, desktopGroup);
00494 } else if (windowType == NET::Dock) {
00495 if (!dockGroup) {
00496 CreateWindowGroup(0, &dockGroup);
00497 SetWindowGroupLevel(dockGroup, kCGDockWindowLevel);
00498 }
00499 SetWindowGroup(win, dockGroup);
00500 ChangeWindowAttributes(win, kWindowNoTitleBarAttribute, kWindowNoAttributes);
00501 }
00502 #else
00503 #warning port me to Mac64
00504 #endif
00505 }
00506
00507 void KWindowSystem::setState( WId win, unsigned long state )
00508 {
00509
00510 kDebug(240) << "KWindowSystem::setState( WId win, unsigned long state ) isn't yet implemented!";
00511 }
00512
00513 void KWindowSystem::clearState( WId win, unsigned long state )
00514 {
00515
00516 kDebug(240) << "KWindowSystem::clearState( WId win, unsigned long state ) isn't yet implemented!";
00517 }
00518
00519 void KWindowSystem::minimizeWindow( WId win, bool animation)
00520 {
00521
00522 kDebug(240) << "KWindowSystem::minimizeWindow( WId win, bool animation) isn't yet implemented!";
00523 }
00524
00525 void KWindowSystem::unminimizeWindow( WId win, bool animation )
00526 {
00527
00528 kDebug(240) << "KWindowSystem::unminimizeWindow( WId win, bool animation ) isn't yet implemented!";
00529 }
00530
00531 void KWindowSystem::raiseWindow( WId win )
00532 {
00533
00534 kDebug(240) << "KWindowSystem::raiseWindow( WId win ) isn't yet implemented!";
00535 }
00536
00537 void KWindowSystem::lowerWindow( WId win )
00538 {
00539
00540 kDebug(240) << "KWindowSystem::lowerWindow( WId win ) isn't yet implemented!";
00541 }
00542
00543 bool KWindowSystem::icccmCompliantMappingState()
00544 {
00545 return false;
00546 }
00547
00548 QRect KWindowSystem::workArea( int desktop )
00549 {
00550
00551 kDebug(240) << "QRect KWindowSystem::workArea( int desktop ) isn't yet implemented!";
00552 return QRect();
00553 }
00554
00555 QRect KWindowSystem::workArea( const QList<WId>& exclude, int desktop )
00556 {
00557
00558 kDebug(240) << "QRect KWindowSystem::workArea( const QList<WId>& exclude, int desktop ) isn't yet implemented!";
00559 return QRect();
00560 }
00561
00562 QString KWindowSystem::desktopName( int desktop )
00563 {
00564 return i18n("Desktop %1", desktop );
00565 }
00566
00567 void KWindowSystem::setDesktopName( int desktop, const QString& name )
00568 {
00569 kDebug(240) << "KWindowSystem::setDesktopName( int desktop, const QString& name ) isn't yet implemented!";
00570
00571 }
00572
00573 bool KWindowSystem::showingDesktop()
00574 {
00575 return false;
00576 }
00577
00578 void KWindowSystem::setUserTime( WId win, long time )
00579 {
00580 kDebug(240) << "KWindowSystem::setUserTime( WId win, long time ) isn't yet implemented!";
00581
00582 }
00583
00584 void KWindowSystem::setExtendedStrut( WId win, int left_width, int left_start, int left_end,
00585 int right_width, int right_start, int right_end, int top_width, int top_start, int top_end,
00586 int bottom_width, int bottom_start, int bottom_end )
00587 {
00588 kDebug(240) << "KWindowSystem::setExtendedStrut isn't yet implemented!";
00589
00590 }
00591
00592 void KWindowSystem::setStrut( WId win, int left, int right, int top, int bottom )
00593 {
00594 kDebug(240) << "KWindowSystem::setStrut isn't yet implemented!";
00595
00596 }
00597
00598 bool KWindowSystem::allowedActionsSupported()
00599 {
00600 return false;
00601 }
00602
00603 QString KWindowSystem::readNameProperty( WId window, unsigned long atom )
00604 {
00605
00606 kDebug(240) << "QString KWindowSystem::readNameProperty( WId window, unsigned long atom ) isn't yet implemented!";
00607 return QString();
00608 }
00609
00610 void KWindowSystem::doNotManage( const QString& title )
00611 {
00612
00613 kDebug(240) << "KWindowSystem::doNotManage( const QString& title ) isn't yet implemented!";
00614 }
00615
00616
00617 void KWindowSystem::connectNotify( const char* signal )
00618 {
00619 kDebug(240) << "connectNotify( const char* signal ) isn't yet implemented!";
00620
00621 }
00622
00623 void KWindowSystem::allowExternalProcessWindowActivation( int pid )
00624 {
00625
00626 }
00627
00628 #include "moc_kwindowsystem.cpp"