not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kwin / utils.cpp
blobe9dc0859413339ba310a1b8546bb62256ede98e8
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
24 This file is for (very) small utility functions/classes.
28 #include "utils.h"
30 #include <unistd.h>
32 #ifndef KCMRULES
34 #include <kxerrorhandler.h>
35 #include <assert.h>
36 #include <kdebug.h>
37 #include <kglobalaccel.h>
38 #include <kshortcut.h>
39 #include <kkeyserver.h>
41 #include <X11/Xlib.h>
42 #include <X11/extensions/shape.h>
43 #include <X11/Xatom.h>
44 #include <QX11Info>
45 #include <QtGui/QKeySequence>
47 #include <stdio.h>
49 #include "atoms.h"
50 #include "notifications.h"
51 #include "workspace.h"
53 #endif
55 namespace KWin
58 #ifndef KCMRULES
60 void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move,
61 bool& minimize, bool& maximize, bool& close )
63 Atom type;
64 int format;
65 unsigned long length, after;
66 unsigned char* data;
67 MwmHints* hints = 0;
68 if ( XGetWindowProperty( display(), w, atoms->motif_wm_hints, 0, 5,
69 false, atoms->motif_wm_hints, &type, &format,
70 &length, &after, &data ) == Success )
72 if ( data )
73 hints = (MwmHints*) data;
75 noborder = false;
76 resize = true;
77 move = true;
78 minimize = true;
79 maximize = true;
80 close = true;
81 if ( hints )
83 // To quote from Metacity 'We support those MWM hints deemed non-stupid'
84 if ( hints->flags & MWM_HINTS_FUNCTIONS )
86 // if MWM_FUNC_ALL is set, other flags say what to turn _off_
87 bool set_value = (( hints->functions & MWM_FUNC_ALL ) == 0 );
88 resize = move = minimize = maximize = close = !set_value;
89 if( hints->functions & MWM_FUNC_RESIZE )
90 resize = set_value;
91 if( hints->functions & MWM_FUNC_MOVE )
92 move = set_value;
93 if( hints->functions & MWM_FUNC_MINIMIZE )
94 minimize = set_value;
95 if( hints->functions & MWM_FUNC_MAXIMIZE )
96 maximize = set_value;
97 if( hints->functions & MWM_FUNC_CLOSE )
98 close = set_value;
100 if ( hints->flags & MWM_HINTS_DECORATIONS )
102 if ( hints->decorations == 0 )
103 noborder = true;
105 XFree( data );
109 //************************************
110 // KWinSelectionOwner
111 //************************************
113 KWinSelectionOwner::KWinSelectionOwner( int screen_P )
114 : KSelectionOwner( make_selection_atom( screen_P ), screen_P )
118 Atom KWinSelectionOwner::make_selection_atom( int screen_P )
120 if( screen_P < 0 )
121 screen_P = DefaultScreen( display());
122 char tmp[ 30 ];
123 sprintf( tmp, "WM_S%d", screen_P );
124 return XInternAtom( display(), tmp, False );
127 void KWinSelectionOwner::getAtoms()
129 KSelectionOwner::getAtoms();
130 if( xa_version == None )
132 Atom atoms[ 1 ];
133 const char* const names[] =
134 { "VERSION" };
135 XInternAtoms( display(), const_cast< char** >( names ), 1, False, atoms );
136 xa_version = atoms[ 0 ];
140 void KWinSelectionOwner::replyTargets( Atom property_P, Window requestor_P )
142 KSelectionOwner::replyTargets( property_P, requestor_P );
143 Atom atoms[ 1 ] = { xa_version };
144 // PropModeAppend !
145 XChangeProperty( display(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend,
146 reinterpret_cast< unsigned char* >( atoms ), 1 );
149 bool KWinSelectionOwner::genericReply( Atom target_P, Atom property_P, Window requestor_P )
151 if( target_P == xa_version )
153 long version[] = { 2, 0 };
154 XChangeProperty( display(), requestor_P, property_P, XA_INTEGER, 32,
155 PropModeReplace, reinterpret_cast< unsigned char* >( &version ), 2 );
157 else
158 return KSelectionOwner::genericReply( target_P, property_P, requestor_P );
159 return true;
162 Atom KWinSelectionOwner::xa_version = None;
165 QByteArray getStringProperty(WId w, Atom prop, char separator)
167 Atom type;
168 int format, status;
169 unsigned long nitems = 0;
170 unsigned long extra = 0;
171 unsigned char *data = 0;
172 QByteArray result = "";
173 KXErrorHandler handler; // ignore errors
174 status = XGetWindowProperty( display(), w, prop, 0, 10000,
175 false, XA_STRING, &type, &format,
176 &nitems, &extra, &data );
177 if ( status == Success)
179 if (data && separator)
181 for (int i=0; i<(int)nitems; i++)
182 if (!data[i] && i+1<(int)nitems)
183 data[i] = separator;
185 if (data)
186 result = (const char*) data;
187 XFree(data);
189 return result;
192 static Time next_x_time;
193 static Bool update_x_time_predicate( Display*, XEvent* event, XPointer )
195 if( next_x_time != CurrentTime )
196 return False;
197 // from qapplication_x11.cpp
198 switch ( event->type ) {
199 case ButtonPress:
200 // fallthrough intended
201 case ButtonRelease:
202 next_x_time = event->xbutton.time;
203 break;
204 case MotionNotify:
205 next_x_time = event->xmotion.time;
206 break;
207 case KeyPress:
208 // fallthrough intended
209 case KeyRelease:
210 next_x_time = event->xkey.time;
211 break;
212 case PropertyNotify:
213 next_x_time = event->xproperty.time;
214 break;
215 case EnterNotify:
216 case LeaveNotify:
217 next_x_time = event->xcrossing.time;
218 break;
219 case SelectionClear:
220 next_x_time = event->xselectionclear.time;
221 break;
222 default:
223 break;
225 return False;
229 Updates xTime(). This used to simply fetch current timestamp from the server,
230 but that can cause xTime() to be newer than timestamp of events that are
231 still in our events queue, thus e.g. making XSetInputFocus() caused by such
232 event to be ignored. Therefore events queue is searched for first
233 event with timestamp, and extra PropertyNotify is generated in order to make
234 sure such event is found.
236 void updateXTime()
238 static QWidget* w = 0;
239 if ( !w )
240 w = new QWidget;
241 long data = 1;
242 XChangeProperty(display(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32,
243 PropModeAppend, (unsigned char*) &data, 1);
244 next_x_time = CurrentTime;
245 XEvent dummy;
246 XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL );
247 if( next_x_time == CurrentTime )
249 XSync( display(), False );
250 XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL );
252 assert( next_x_time != CurrentTime );
253 QX11Info::setAppTime( next_x_time );
254 XEvent ev; // remove the PropertyNotify event from the events queue
255 XWindowEvent( display(), w->winId(), PropertyChangeMask, &ev );
258 static int server_grab_count = 0;
260 void grabXServer()
262 if( ++server_grab_count == 1 )
263 XGrabServer( display());
266 void ungrabXServer()
268 assert( server_grab_count > 0 );
269 if( --server_grab_count == 0 )
271 XUngrabServer( display());
272 XFlush( display());
273 Notify::sendPendingEvents();
277 bool grabbedXServer()
279 return server_grab_count > 0;
282 static bool keyboard_grabbed = false;
284 bool grabXKeyboard( Window w )
286 if( QWidget::keyboardGrabber() != NULL )
287 return false;
288 if( keyboard_grabbed )
289 return false;
290 if( qApp->activePopupWidget() != NULL )
291 return false;
292 if( w == None )
293 w = rootWindow();
294 if( XGrabKeyboard( display(), w, False,
295 GrabModeAsync, GrabModeAsync, xTime()) != GrabSuccess )
296 return false;
297 keyboard_grabbed = true;
298 return true;
301 void ungrabXKeyboard()
303 if( !keyboard_grabbed )
304 { // grabXKeyboard() may fail sometimes, so don't fail, but at least warn anyway
305 kDebug(1212) << "ungrabXKeyboard() called but keyboard not grabbed!";
307 keyboard_grabbed = false;
308 XUngrabKeyboard( display(), xTime());
311 QPoint cursorPos()
313 return Workspace::self()->cursorPos();
316 // converting between X11 mouse/keyboard state mask and Qt button/keyboard states
318 int qtToX11Button( Qt::MouseButton button )
320 if( button == Qt::LeftButton )
321 return Button1;
322 else if( button == Qt::MidButton )
323 return Button2;
324 else if( button == Qt::RightButton )
325 return Button3;
326 return AnyButton; // 0
329 Qt::MouseButton x11ToQtMouseButton( int button )
331 if( button == Button1 )
332 return Qt::LeftButton;
333 if( button == Button2 )
334 return Qt::MidButton;
335 if( button == Button3 )
336 return Qt::RightButton;
337 return Qt::NoButton;
340 int qtToX11State( Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers )
342 int ret = 0;
343 if( buttons & Qt::LeftButton )
344 ret |= Button1Mask;
345 if( buttons & Qt::MidButton )
346 ret |= Button2Mask;
347 if( buttons & Qt::RightButton )
348 ret |= Button3Mask;
349 if( modifiers & Qt::ShiftModifier )
350 ret |= ShiftMask;
351 if( modifiers & Qt::ControlModifier )
352 ret |= ControlMask;
353 if( modifiers & Qt::AltModifier )
354 ret |= KKeyServer::modXAlt();
355 if( modifiers & Qt::MetaModifier )
356 ret |= KKeyServer::modXMeta();
357 return ret;
360 Qt::MouseButtons x11ToQtMouseButtons( int state )
362 Qt::MouseButtons ret = 0;
363 if( state & Button1Mask )
364 ret |= Qt::LeftButton;
365 if( state & Button2Mask )
366 ret |= Qt::MidButton;
367 if( state & Button3Mask )
368 ret |= Qt::RightButton;
369 return ret;
372 Qt::KeyboardModifiers x11ToQtKeyboardModifiers( int state )
374 Qt::KeyboardModifiers ret = 0;
375 if( state & ShiftMask )
376 ret |= Qt::ShiftModifier;
377 if( state & ControlMask )
378 ret |= Qt::ControlModifier;
379 if( state & KKeyServer::modXAlt())
380 ret |= Qt::AltModifier;
381 if( state & KKeyServer::modXMeta())
382 ret |= Qt::MetaModifier;
383 return ret;
386 #endif
388 bool isLocalMachine( const QByteArray& host )
390 #ifdef HOST_NAME_MAX
391 char hostnamebuf[HOST_NAME_MAX];
392 #else
393 char hostnamebuf[256];
394 #endif
395 if (gethostname (hostnamebuf, sizeof hostnamebuf) >= 0)
397 hostnamebuf[sizeof(hostnamebuf)-1] = 0;
398 if (host == hostnamebuf)
399 return true;
400 if( char *dot = strchr(hostnamebuf, '.'))
402 *dot = '\0';
403 if( host == hostnamebuf )
404 return true;
407 return false;
410 #ifndef KCMRULES
411 ShortcutDialog::ShortcutDialog( const QKeySequence& cut )
412 : widget( new KKeySequenceWidget( this ))
413 ,_shortcut(cut)
415 widget->setKeySequence( cut );
417 // To not check for conflicting shortcuts. The widget would use a message
418 // box which brings down kwin.
419 widget->setCheckForConflictsAgainst(KKeySequenceWidget::None);
420 // It's a global shortcut so don't allow multikey shortcuts
421 widget->setMultiKeyShortcutsAllowed(false);
423 // Listen to changed shortcuts
424 connect(
425 widget, SIGNAL(keySequenceChanged(const QKeySequence&)),
426 SLOT(keySequenceChanged(const QKeySequence&)));
428 setMainWidget( widget );
430 // make it a popup, so that it has the grab
431 XSetWindowAttributes attrs;
432 attrs.override_redirect = True;
433 XChangeWindowAttributes( display(), winId(), CWOverrideRedirect, &attrs );
434 setWindowFlags( Qt::Popup );
437 void ShortcutDialog::accept()
439 QKeySequence seq = shortcut();
440 if( !seq.isEmpty())
442 if( seq[0] == Qt::Key_Escape )
444 reject();
445 return;
447 if( seq[0] == Qt::Key_Space
448 || (seq[0] & Qt::KeyboardModifierMask) == 0 )
449 { // clear
450 widget->clearKeySequence();
451 KDialog::accept();
452 return;
455 KDialog::accept();
458 void ShortcutDialog::done( int r )
460 KDialog::done( r );
461 emit dialogDone( r == Accepted );
464 void ShortcutDialog::keySequenceChanged(const QKeySequence &seq)
466 // Check if the key sequence is used currently
467 QList<KGlobalShortcutInfo> conflicting = KGlobalAccel::getGlobalShortcutsByKey(seq);
468 if (!conflicting.isEmpty()) {
469 kDebug(1212) << "TODO: Display conflicting shortcuts to user";
470 // TODO: Inform the user somehow instead of just ignoring his wish
471 widget->setKeySequence(shortcut());
473 _shortcut = seq;
476 QKeySequence ShortcutDialog::shortcut() const
478 return _shortcut;
481 #endif //KCMRULES
482 } // namespace
484 #ifndef KCMRULES
485 #include "utils.moc"
486 #endif