~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy-backports

« back to all changes in this revision

Viewing changes to kwin/utils.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-09-05 20:45:14 UTC
  • Revision ID: james.westby@ubuntu.com-20070905204514-632hhspl0nvrc84i
Tags: upstream-3.93.0
ImportĀ upstreamĀ versionĀ 3.93.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************
 
2
 KWin - the KDE window manager
 
3
 This file is part of the KDE project.
 
4
 
 
5
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
 
6
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
 
7
 
 
8
You can Freely distribute this program under the GNU General Public
 
9
License. See the file "COPYING" for the exact licensing terms.
 
10
******************************************************************/
 
11
 
 
12
/*
 
13
 
 
14
 This file is for (very) small utility functions/classes.
 
15
 
 
16
*/
 
17
 
 
18
#include "utils.h"
 
19
 
 
20
#include <unistd.h>
 
21
 
 
22
#ifndef KCMRULES
 
23
 
 
24
#include <kxerrorhandler.h>
 
25
#include <assert.h>
 
26
#include <kdebug.h>
 
27
#include <kshortcut.h>
 
28
#include <kkeyserver.h>
 
29
 
 
30
#include <X11/Xlib.h>
 
31
#include <X11/extensions/shape.h>
 
32
#include <X11/Xatom.h>
 
33
#include <QX11Info>
 
34
 
 
35
#ifdef HAVE_XRENDER
 
36
#include <X11/extensions/Xrender.h>
 
37
#endif
 
38
#ifdef HAVE_XFIXES
 
39
#include <X11/extensions/Xfixes.h>
 
40
#endif
 
41
#ifdef HAVE_XDAMAGE
 
42
#include <X11/extensions/Xdamage.h>
 
43
#endif
 
44
#ifdef HAVE_XRANDR
 
45
#include <X11/extensions/Xrandr.h>
 
46
#endif
 
47
#ifdef HAVE_XCOMPOSITE
 
48
#include <X11/extensions/Xcomposite.h>
 
49
#endif
 
50
#ifdef HAVE_OPENGL
 
51
#include <GL/glx.h>
 
52
#endif
 
53
#ifdef HAVE_XSYNC
 
54
#include <X11/extensions/sync.h>
 
55
#endif
 
56
 
 
57
#include <stdio.h>
 
58
 
 
59
#include "atoms.h"
 
60
#include "notifications.h"
 
61
#include "workspace.h"
 
62
 
 
63
#endif
 
64
 
 
65
namespace KWin
 
66
{
 
67
 
 
68
#ifndef KCMRULES
 
69
 
 
70
int Extensions::shape_version = 0;
 
71
int Extensions::shape_event_base = 0;
 
72
bool Extensions::has_randr = false;
 
73
int Extensions::randr_event_base = 0;
 
74
bool Extensions::has_damage = false;
 
75
int Extensions::damage_event_base = 0;
 
76
int Extensions::composite_version = 0;
 
77
int Extensions::fixes_version = 0;
 
78
int Extensions::render_version = 0;
 
79
bool Extensions::has_glx = false;
 
80
bool Extensions::has_sync = false;
 
81
int Extensions::sync_event_base = 0;
 
82
 
 
83
void Extensions::init()
 
84
    {
 
85
    int dummy;
 
86
    shape_version = 0;
 
87
    if( XShapeQueryExtension( display(), &shape_event_base, &dummy ))
 
88
        {
 
89
        int major, minor;
 
90
        if( XShapeQueryVersion( display(), &major, &minor ))
 
91
            shape_version = major * 0x10 + minor;
 
92
        }
 
93
#ifdef HAVE_XRANDR
 
94
    has_randr = XRRQueryExtension( display(), &randr_event_base, &dummy );
 
95
    if( has_randr )
 
96
        {
 
97
        int major, minor;
 
98
        XRRQueryVersion( display(), &major, &minor );
 
99
        has_randr = ( major > 1 || ( major == 1 && minor >= 1 ) );
 
100
        }
 
101
#else
 
102
    has_randr = false;
 
103
#endif
 
104
#ifdef HAVE_XDAMAGE
 
105
    has_damage = XDamageQueryExtension( display(), &damage_event_base, &dummy );
 
106
#else
 
107
    has_damage = false;
 
108
#endif
 
109
    composite_version = 0;
 
110
#ifdef HAVE_XCOMPOSITE
 
111
    if( XCompositeQueryExtension( display(), &dummy, &dummy ))
 
112
        {
 
113
        int major = 0, minor = 0;
 
114
        XCompositeQueryVersion( display(), &major, &minor );
 
115
        composite_version = major * 0x10 + minor;
 
116
        }
 
117
#endif
 
118
    fixes_version = 0;
 
119
#ifdef HAVE_XFIXES
 
120
    if( XFixesQueryExtension( display(), &dummy, &dummy ))
 
121
        {
 
122
        int major = 0, minor = 0;
 
123
        XFixesQueryVersion( display(), &major, &minor );
 
124
        fixes_version = major * 0x10 + minor;
 
125
        }
 
126
#endif
 
127
    render_version = 0;
 
128
#ifdef HAVE_XRENDER
 
129
    if( XRenderQueryExtension( display(), &dummy, &dummy ))
 
130
        {
 
131
        int major = 0, minor = 0;
 
132
        XRenderQueryVersion( display(), &major, &minor );
 
133
        render_version = major * 0x10 + minor;
 
134
        }
 
135
#endif
 
136
    has_glx = false;
 
137
#ifdef HAVE_OPENGL
 
138
    has_glx = glXQueryExtension( display(), &dummy, &dummy );
 
139
#endif
 
140
#ifdef HAVE_XSYNC
 
141
    if( XSyncQueryExtension( display(), &sync_event_base, &dummy ))
 
142
        {
 
143
        int major = 0, minor = 0;
 
144
        if( XSyncInitialize( display(), &major, &minor ))
 
145
            has_sync = true;
 
146
        }
 
147
#endif
 
148
    kDebug( 1212 ) << "Extensions: shape: 0x" << QString::number( shape_version, 16 )
 
149
        << " composite: 0x" << QString::number( composite_version, 16 )
 
150
        << " render: 0x" << QString::number( render_version, 16 )
 
151
        << " fixes: 0x" << QString::number( fixes_version, 16 ) << endl;
 
152
    }
 
153
 
 
154
int Extensions::shapeNotifyEvent()
 
155
    {
 
156
    return shape_event_base + ShapeNotify;
 
157
    }
 
158
 
 
159
// does the window w need a shape combine mask around it?
 
160
bool Extensions::hasShape( Window w )
 
161
    {
 
162
    int xws, yws, xbs, ybs;
 
163
    unsigned int wws, hws, wbs, hbs;
 
164
    int boundingShaped = 0, clipShaped = 0;
 
165
    if( !shapeAvailable())
 
166
        return false;
 
167
    XShapeQueryExtents(display(), w,
 
168
                       &boundingShaped, &xws, &yws, &wws, &hws,
 
169
                       &clipShaped, &xbs, &ybs, &wbs, &hbs);
 
170
    return boundingShaped != 0;
 
171
    }
 
172
 
 
173
bool Extensions::shapeInputAvailable()
 
174
    {
 
175
    return shape_version >= 0x11; // 1.1
 
176
    }
 
177
 
 
178
int Extensions::randrNotifyEvent()
 
179
    {
 
180
#ifdef HAVE_XRANDR
 
181
    return randr_event_base + RRScreenChangeNotify;
 
182
#else
 
183
    return 0;
 
184
#endif
 
185
    }
 
186
 
 
187
int Extensions::damageNotifyEvent()
 
188
    {
 
189
#ifdef HAVE_XDAMAGE
 
190
    return damage_event_base + XDamageNotify;
 
191
#else
 
192
    return 0;
 
193
#endif
 
194
    }
 
195
 
 
196
bool Extensions::compositeOverlayAvailable()
 
197
    {
 
198
    return composite_version >= 0x03; // 0.3
 
199
    }
 
200
 
 
201
bool Extensions::fixesRegionAvailable()
 
202
    {
 
203
    return fixes_version >= 0x30; // 3
 
204
    }
 
205
 
 
206
int Extensions::syncAlarmNotifyEvent()
 
207
    {
 
208
#ifdef HAVE_XSYNC
 
209
    return sync_event_base + XSyncAlarmNotify;
 
210
#else
 
211
    return 0;
 
212
#endif
 
213
    }
 
214
 
 
215
void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
 
216
    bool& minimize, bool& maximize, bool& close )
 
217
    {
 
218
    Atom type;
 
219
    int format;
 
220
    unsigned long length, after;
 
221
    unsigned char* data;
 
222
    MwmHints* hints = 0;
 
223
    if ( XGetWindowProperty( display(), w, atoms->motif_wm_hints, 0, 5,
 
224
                             false, atoms->motif_wm_hints, &type, &format,
 
225
                             &length, &after, &data ) == Success ) 
 
226
        {
 
227
        if ( data )
 
228
            hints = (MwmHints*) data;
 
229
        }
 
230
    noborder = false;
 
231
    resize = true;
 
232
    move = true;
 
233
    minimize = true;
 
234
    maximize = true;
 
235
    close = true;
 
236
    if ( hints ) 
 
237
        {
 
238
    // To quote from Metacity 'We support those MWM hints deemed non-stupid'
 
239
        if ( hints->flags & MWM_HINTS_FUNCTIONS ) 
 
240
            {
 
241
            // if MWM_FUNC_ALL is set, other flags say what to turn _off_
 
242
            bool set_value = (( hints->functions & MWM_FUNC_ALL ) == 0 );
 
243
            resize = move = minimize = maximize = close = !set_value;
 
244
            if( hints->functions & MWM_FUNC_RESIZE )
 
245
                resize = set_value;
 
246
            if( hints->functions & MWM_FUNC_MOVE )
 
247
                move = set_value;
 
248
            if( hints->functions & MWM_FUNC_MINIMIZE )
 
249
                minimize = set_value;
 
250
            if( hints->functions & MWM_FUNC_MAXIMIZE )
 
251
                maximize = set_value;
 
252
            if( hints->functions & MWM_FUNC_CLOSE )
 
253
                close = set_value;
 
254
            }
 
255
        if ( hints->flags & MWM_HINTS_DECORATIONS ) 
 
256
            {
 
257
            if ( hints->decorations == 0 )
 
258
                noborder = true;
 
259
            }
 
260
        XFree( data );
 
261
        }
 
262
    }
 
263
 
 
264
//************************************
 
265
// KWinSelectionOwner
 
266
//************************************
 
267
 
 
268
KWinSelectionOwner::KWinSelectionOwner( int screen_P )
 
269
    : KSelectionOwner( make_selection_atom( screen_P ), screen_P )
 
270
    {
 
271
    }
 
272
 
 
273
Atom KWinSelectionOwner::make_selection_atom( int screen_P )
 
274
    {
 
275
    if( screen_P < 0 )
 
276
        screen_P = DefaultScreen( display());
 
277
    char tmp[ 30 ];
 
278
    sprintf( tmp, "WM_S%d", screen_P );
 
279
    return XInternAtom( display(), tmp, False );
 
280
    }
 
281
 
 
282
void KWinSelectionOwner::getAtoms()
 
283
    {
 
284
    KSelectionOwner::getAtoms();
 
285
    if( xa_version == None )
 
286
        {
 
287
        Atom atoms[ 1 ];
 
288
        const char* const names[] =
 
289
            { "VERSION" };
 
290
        XInternAtoms( display(), const_cast< char** >( names ), 1, False, atoms );
 
291
        xa_version = atoms[ 0 ];
 
292
        }
 
293
    }
 
294
 
 
295
void KWinSelectionOwner::replyTargets( Atom property_P, Window requestor_P )
 
296
    {
 
297
    KSelectionOwner::replyTargets( property_P, requestor_P );
 
298
    Atom atoms[ 1 ] = { xa_version };
 
299
    // PropModeAppend !
 
300
    XChangeProperty( display(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend,
 
301
        reinterpret_cast< unsigned char* >( atoms ), 1 );
 
302
    }
 
303
 
 
304
bool KWinSelectionOwner::genericReply( Atom target_P, Atom property_P, Window requestor_P )
 
305
    {
 
306
    if( target_P == xa_version )
 
307
        {
 
308
        long version[] = { 2, 0 };
 
309
        XChangeProperty( display(), requestor_P, property_P, XA_INTEGER, 32,
 
310
            PropModeReplace, reinterpret_cast< unsigned char* >( &version ), 2 );
 
311
        }
 
312
    else
 
313
        return KSelectionOwner::genericReply( target_P, property_P, requestor_P );
 
314
    return true;    
 
315
    }
 
316
 
 
317
Atom KWinSelectionOwner::xa_version = None;
 
318
 
 
319
 
 
320
QByteArray getStringProperty(WId w, Atom prop, char separator)
 
321
    {
 
322
    Atom type;
 
323
    int format, status;
 
324
    unsigned long nitems = 0;
 
325
    unsigned long extra = 0;
 
326
    unsigned char *data = 0;
 
327
    QByteArray result = "";
 
328
    KXErrorHandler handler; // ignore errors
 
329
    status = XGetWindowProperty( display(), w, prop, 0, 10000,
 
330
                                 false, XA_STRING, &type, &format,
 
331
                                 &nitems, &extra, &data );
 
332
    if ( status == Success) 
 
333
        {
 
334
        if (data && separator) 
 
335
            {
 
336
            for (int i=0; i<(int)nitems; i++)
 
337
                if (!data[i] && i+1<(int)nitems)
 
338
                    data[i] = separator;
 
339
            }
 
340
        if (data)
 
341
            result = (const char*) data;
 
342
        XFree(data);
 
343
        }
 
344
    return result;
 
345
    }
 
346
 
 
347
static Time next_x_time;
 
348
static Bool update_x_time_predicate( Display*, XEvent* event, XPointer )
 
349
{
 
350
    if( next_x_time != CurrentTime )
 
351
        return False;
 
352
    // from qapplication_x11.cpp
 
353
    switch ( event->type ) {
 
354
    case ButtonPress:
 
355
        // fallthrough intended
 
356
    case ButtonRelease:
 
357
        next_x_time = event->xbutton.time;
 
358
        break;
 
359
    case MotionNotify:
 
360
        next_x_time = event->xmotion.time;
 
361
        break;
 
362
    case KeyPress:
 
363
        // fallthrough intended
 
364
    case KeyRelease:
 
365
        next_x_time = event->xkey.time;
 
366
        break;
 
367
    case PropertyNotify:
 
368
        next_x_time = event->xproperty.time;
 
369
        break;
 
370
    case EnterNotify:
 
371
    case LeaveNotify:
 
372
        next_x_time = event->xcrossing.time;
 
373
        break;
 
374
    case SelectionClear:
 
375
        next_x_time = event->xselectionclear.time;
 
376
        break;
 
377
    default:
 
378
        break;
 
379
    }
 
380
    return False;
 
381
}
 
382
 
 
383
/*
 
384
 Updates xTime(). This used to simply fetch current timestamp from the server,
 
385
 but that can cause xTime() to be newer than timestamp of events that are
 
386
 still in our events queue, thus e.g. making XSetInputFocus() caused by such
 
387
 event to be ignored. Therefore events queue is searched for first
 
388
 event with timestamp, and extra PropertyNotify is generated in order to make
 
389
 sure such event is found.
 
390
*/
 
391
void updateXTime()
 
392
    {
 
393
    static QWidget* w = 0;
 
394
    if ( !w )
 
395
        w = new QWidget;
 
396
    long data = 1;
 
397
    XChangeProperty(display(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
 
398
                    PropModeAppend, (unsigned char*) &data, 1);
 
399
    next_x_time = CurrentTime;
 
400
    XEvent dummy;
 
401
    XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL );
 
402
    if( next_x_time == CurrentTime )
 
403
        {
 
404
        XSync( display(), False );
 
405
        XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL );
 
406
        }
 
407
    assert( next_x_time != CurrentTime );
 
408
    QX11Info::setAppTime( next_x_time );
 
409
    XEvent ev; // remove the PropertyNotify event from the events queue
 
410
    XWindowEvent( display(), w->winId(), PropertyChangeMask, &ev );
 
411
    }
 
412
 
 
413
static int server_grab_count = 0;
 
414
 
 
415
void grabXServer()
 
416
    {
 
417
    if( ++server_grab_count == 1 )
 
418
        XGrabServer( display());
 
419
    }
 
420
 
 
421
void ungrabXServer()
 
422
    {
 
423
    assert( server_grab_count > 0 );
 
424
    if( --server_grab_count == 0 )
 
425
        {
 
426
        XUngrabServer( display());
 
427
        XFlush( display());
 
428
        Notify::sendPendingEvents();
 
429
        }
 
430
    }
 
431
 
 
432
bool grabbedXServer()
 
433
    {
 
434
    return server_grab_count > 0;
 
435
    }
 
436
 
 
437
static bool keyboard_grabbed = false;
 
438
 
 
439
bool grabXKeyboard( Window w )
 
440
    {
 
441
    if( QWidget::keyboardGrabber() != NULL )
 
442
        return false;
 
443
    if( keyboard_grabbed )
 
444
        return false;
 
445
    if( qApp->activePopupWidget() != NULL )
 
446
        return false;
 
447
    if( w == None )
 
448
        w = rootWindow();
 
449
    if( XGrabKeyboard( display(), w, False,
 
450
        GrabModeAsync, GrabModeAsync, xTime()) != GrabSuccess )
 
451
        return false;
 
452
    keyboard_grabbed = true;
 
453
    return true;
 
454
    }
 
455
 
 
456
void ungrabXKeyboard()
 
457
    {
 
458
    assert( keyboard_grabbed );
 
459
    keyboard_grabbed = false;
 
460
    XUngrabKeyboard( display(), xTime());
 
461
    }
 
462
 
 
463
QPoint cursorPos()
 
464
    {
 
465
    return Workspace::self()->cursorPos();
 
466
    }
 
467
 
 
468
// converting between X11 mouse/keyboard state mask and Qt button/keyboard states
 
469
 
 
470
int qtToX11Button( Qt::MouseButton button )
 
471
    {
 
472
    if( button == Qt::LeftButton )
 
473
        return Button1;
 
474
    else if( button == Qt::MidButton )
 
475
        return Button2;
 
476
    else if( button == Qt::RightButton )
 
477
        return Button3;
 
478
    return AnyButton; // 0
 
479
    }
 
480
 
 
481
Qt::MouseButton x11ToQtMouseButton( int button )
 
482
    {
 
483
    if( button == Button1 )
 
484
        return Qt::LeftButton;
 
485
    if( button == Button2 )
 
486
        return Qt::MidButton;
 
487
    if( button == Button3 )
 
488
        return Qt::RightButton;
 
489
    return Qt::NoButton;
 
490
    }
 
491
 
 
492
int qtToX11State( Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers )
 
493
    {
 
494
    int ret = 0;
 
495
    if( buttons & Qt::LeftButton )
 
496
        ret |= Button1Mask;
 
497
    if( buttons & Qt::MidButton )
 
498
        ret |= Button2Mask;
 
499
    if( buttons & Qt::RightButton )
 
500
        ret |= Button3Mask;
 
501
    if( modifiers & Qt::ShiftModifier )
 
502
        ret |= ShiftMask;
 
503
    if( modifiers & Qt::ControlModifier )
 
504
        ret |= ControlMask;
 
505
    if( modifiers & Qt::AltModifier )
 
506
        ret |= KKeyServer::modXAlt();
 
507
    if( modifiers & Qt::MetaModifier )
 
508
        ret |= KKeyServer::modXMeta();
 
509
    return ret;
 
510
    }
 
511
 
 
512
Qt::MouseButtons x11ToQtMouseButtons( int state )
 
513
    {
 
514
    Qt::MouseButtons ret = 0;
 
515
    if( state & Button1Mask )
 
516
        ret |= Qt::LeftButton;
 
517
    if( state & Button2Mask )
 
518
        ret |= Qt::MidButton;
 
519
    if( state & Button3Mask )
 
520
        ret |= Qt::RightButton;
 
521
    return ret;
 
522
    }
 
523
 
 
524
Qt::KeyboardModifiers x11ToQtKeyboardModifiers( int state )
 
525
    {
 
526
    Qt::KeyboardModifiers ret = 0;
 
527
    if( state & ShiftMask )
 
528
        ret |= Qt::ShiftModifier;
 
529
    if( state & ControlMask )
 
530
        ret |= Qt::ControlModifier;
 
531
    if( state & KKeyServer::modXAlt())
 
532
        ret |= Qt::AltModifier;
 
533
    if( state & KKeyServer::modXMeta())
 
534
        ret |= Qt::MetaModifier;
 
535
    return ret;
 
536
    }
 
537
 
 
538
#endif
 
539
 
 
540
bool isLocalMachine( const QByteArray& host )
 
541
    {
 
542
#ifdef HOST_NAME_MAX
 
543
    char hostnamebuf[HOST_NAME_MAX];
 
544
#else
 
545
    char hostnamebuf[256];
 
546
#endif
 
547
    if (gethostname (hostnamebuf, sizeof hostnamebuf) >= 0) 
 
548
        {
 
549
        hostnamebuf[sizeof(hostnamebuf)-1] = 0;
 
550
        if (host == hostnamebuf)
 
551
            return true;
 
552
        if( char *dot = strchr(hostnamebuf, '.'))
 
553
            {
 
554
            *dot = '\0';
 
555
            if( host == hostnamebuf )
 
556
                return true;
 
557
            }
 
558
        }
 
559
    return false;
 
560
    }
 
561
 
 
562
#ifndef KCMRULES
 
563
#ifdef __GNUC__
 
564
#warning KShortcutDialog is gone
 
565
#endif //__GNUC__
 
566
#if 0
 
567
ShortcutDialog::ShortcutDialog( const KShortcut& cut )
 
568
    : KShortcutDialog( cut, false /*TODO: ???*/ )
 
569
    {
 
570
    // make it a popup, so that it has the grab
 
571
    XSetWindowAttributes attrs;
 
572
    attrs.override_redirect = True;
 
573
    XChangeWindowAttributes( display(), winId(), CWOverrideRedirect, &attrs );
 
574
    setWindowFlags( Qt::Popup );
 
575
    }
 
576
 
 
577
void ShortcutDialog::accept()
 
578
    {
 
579
    foreach( const QKeySequence &seq, shortcut() )
 
580
        {
 
581
        if( seq.isEmpty())
 
582
            break;
 
583
        if( seq[0] == Qt::Key_Escape )
 
584
            {
 
585
            reject();
 
586
            return;
 
587
            }
 
588
        if( seq[0] == Qt::Key_Space )
 
589
            { // clear
 
590
            setShortcut( KShortcut());
 
591
            KShortcutDialog::accept();
 
592
            return;
 
593
            }
 
594
        if( (seq[0] & Qt::KeyboardModifierMask) == 0 )
 
595
            { // no shortcuts without modifiers
 
596
            KShortcut cut = shortcut();
 
597
            cut.remove( seq );
 
598
            setShortcut( cut );
 
599
            return;
 
600
            }
 
601
        }
 
602
    KShortcutDialog::accept();
 
603
    }
 
604
#endif //0
 
605
#endif //KCMRULES
 
606
} // namespace
 
607
 
 
608
#ifndef KCMRULES
 
609
#include "utils.moc"
 
610
#endif