• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • sources
  • kde-4.12
  • kdelibs
  • kdeui
  • widgets
kmenubar.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 1997, 1998, 1999, 2000 Sven Radej (radej@kde.org)
3  Copyright (C) 1997, 1998, 1999, 2000 Matthias Ettrich (ettrich@kde.org)
4  Copyright (C) 1999, 2000 Daniel "Mosfet" Duley (mosfet@kde.org)
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 #include "kmenubar.h"
24 
25 #include <config.h>
26 
27 #include <stdio.h>
28 
29 #include <QtCore/QObject>
30 #include <QtCore/QTimer>
31 #include <QtGui/QActionEvent>
32 #include <QtGui/QDesktopWidget>
33 #include <QtGui/QMenuItem>
34 #include <QtGui/QPainter>
35 #include <QtGui/QStyle>
36 #include <QtGui/QStyleOptionMenuItem>
37 
38 #include <kconfig.h>
39 #include <kglobalsettings.h>
40 #include <kapplication.h>
41 #include <kglobal.h>
42 #include <kdebug.h>
43 #include <kmanagerselection.h>
44 #include <kconfiggroup.h>
45 #include <kwindowsystem.h>
46 
47 #ifdef Q_WS_X11
48 #include <qx11info_x11.h>
49 
50 #include <X11/Xlib.h>
51 #include <X11/Xutil.h>
52 #include <X11/Xatom.h>
53 #endif
54 
55 /*
56 
57  Toplevel menubar (not for the fallback size handling done by itself):
58  - should not alter position or set strut
59  - every toplevel must have at most one matching topmenu
60  - embedder won't allow shrinking below a certain size
61  - must have WM_TRANSIENT_FOR pointing the its mainwindow
62  - the exception is desktop's menubar, which can be transient for root window
63  because of using root window as the desktop window
64  - Fitts' Law
65 
66 */
67 
68 static int block_resize = 0;
69 
70 class KMenuBar::KMenuBarPrivate
71 {
72 public:
73  KMenuBarPrivate()
74  : forcedTopLevel( false ),
75  topLevel( false ),
76  wasTopLevel( false ),
77 #ifdef Q_WS_X11
78  selection( NULL ),
79 #endif
80  min_size( 0, 0 )
81  {
82  }
83  ~KMenuBarPrivate()
84  {
85 #ifdef Q_WS_X11
86  delete selection;
87 #endif
88  }
89  int frameStyle; // only valid in toplevel mode
90  int lineWidth; // dtto
91  int margin; // dtto
92  bool fallback_mode : 1; // dtto
93 
94  bool forcedTopLevel : 1;
95  bool topLevel : 1;
96  bool wasTopLevel : 1; // when TLW is fullscreen, remember state
97 
98 #ifdef Q_WS_X11
99  KSelectionWatcher* selection;
100 #endif
101  QTimer selection_timer;
102  QSize min_size;
103  static Atom makeSelectionAtom();
104 };
105 
106 #ifdef Q_WS_X11
107 static Atom selection_atom = None;
108 static Atom msg_type_atom = None;
109 
110 static
111 void initAtoms()
112 {
113  char nm[ 100 ];
114  sprintf( nm, "_KDE_TOPMENU_OWNER_S%d", DefaultScreen( QX11Info::display()));
115  char nm2[] = "_KDE_TOPMENU_MINSIZE";
116  char* names[ 2 ] = { nm, nm2 };
117  Atom atoms[ 2 ];
118  XInternAtoms( QX11Info::display(), names, 2, False, atoms );
119  selection_atom = atoms[ 0 ];
120  msg_type_atom = atoms[ 1 ];
121 }
122 #endif
123 
124 Atom KMenuBar::KMenuBarPrivate::makeSelectionAtom()
125 {
126 #ifdef Q_WS_X11
127  if( selection_atom == None )
128  initAtoms();
129  return selection_atom;
130 #else
131  return 0;
132 #endif
133 }
134 
135 KMenuBar::KMenuBar(QWidget *parent)
136  : QMenuBar(parent), d(new KMenuBarPrivate)
137 {
138  connect( &d->selection_timer, SIGNAL(timeout()),
139  this, SLOT(selectionTimeout()));
140 
141  connect( qApp->desktop(), SIGNAL(resized(int)), SLOT(updateFallbackSize()));
142 
143  // toolbarAppearanceChanged(int) is sent when changing macstyle
144  connect( KGlobalSettings::self(), SIGNAL(toolbarAppearanceChanged(int)),
145  this, SLOT(slotReadConfig()));
146 
147  slotReadConfig();
148 }
149 
150 KMenuBar::~KMenuBar()
151 {
152  delete d;
153 }
154 
155 void KMenuBar::setTopLevelMenu(bool top_level)
156 {
157  d->forcedTopLevel = top_level;
158  setTopLevelMenuInternal( top_level );
159 }
160 
161 void KMenuBar::setTopLevelMenuInternal(bool top_level)
162 {
163  if (d->forcedTopLevel)
164  top_level = true;
165 
166  d->wasTopLevel = top_level;
167  if( parentWidget()
168  && parentWidget()->topLevelWidget()->isFullScreen())
169  top_level = false;
170 
171  if ( isTopLevelMenu() == top_level )
172  return;
173  d->topLevel = top_level;
174  if ( isTopLevelMenu() )
175  {
176 #ifdef Q_WS_X11
177  d->selection = new KSelectionWatcher( KMenuBarPrivate::makeSelectionAtom(),
178  DefaultScreen( QX11Info::display()));
179  connect( d->selection, SIGNAL(newOwner(Window)),
180  this, SLOT(updateFallbackSize()));
181  connect( d->selection, SIGNAL(lostOwner()),
182  this, SLOT(updateFallbackSize()));
183 #endif
184  d->frameStyle = 0; //frameStyle();
185  d->lineWidth = 0; //lineWidth();
186  d->margin = 0; //margin();
187  d->fallback_mode = false;
188  bool wasShown = !isHidden();
189  setParent(parentWidget(), Qt::Window | Qt::Tool | Qt::FramelessWindowHint);
190  setGeometry(0,0,width(),height());
191 #ifdef Q_WS_X11
192  KWindowSystem::setType( winId(), NET::TopMenu );
193 #endif
194  if( parentWidget())
195  KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
196  //QMenuBar::setFrameStyle( NoFrame );
197  //QMenuBar::setLineWidth( 0 );
198  //QMenuBar::setMargin( 0 );
199  updateFallbackSize();
200  d->min_size = QSize( 0, 0 );
201  if( parentWidget() && !parentWidget()->isTopLevel())
202  setVisible( parentWidget()->isVisible());
203  else if ( wasShown )
204  show();
205  } else
206  {
207 #ifdef Q_WS_X11
208  delete d->selection;
209  d->selection = NULL;
210 #endif
211  setAttribute(Qt::WA_NoSystemBackground, false);
212  setBackgroundRole(QPalette::Button);
213  setFrameStyle( d->frameStyle );
214  setLineWidth( d->lineWidth );
215  setMargin( d->margin );
216  setMinimumSize( 0, 0 );
217  setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
218  updateMenuBarSize();
219  if ( parentWidget() )
220  setParent( parentWidget() );
221  }
222 }
223 
224 bool KMenuBar::isTopLevelMenu() const
225 {
226  return d->topLevel;
227 }
228 
229 
230 void KMenuBar::slotReadConfig()
231 {
232  KConfigGroup cg( KGlobal::config(), "KDE" );
233  setTopLevelMenuInternal( cg.readEntry( "macStyle", false ) );
234 }
235 
236 bool KMenuBar::eventFilter(QObject *obj, QEvent *ev)
237 {
238  if ( d->topLevel )
239  {
240  if ( parentWidget() && obj == parentWidget()->topLevelWidget() )
241  {
242  if( ev->type() == QEvent::Resize )
243  return false; // ignore resizing of parent, QMenuBar would try to adjust size
244 #ifdef QT3_SUPPORT
245  if ( ev->type() == QEvent::Accel || ev->type() == QEvent::AccelAvailable )
246  {
247  if ( QApplication::sendEvent( topLevelWidget(), ev ) )
248  return true;
249  }
250 #endif
251  /* FIXME QEvent::ShowFullScreen is no more
252  if(ev->type() == QEvent::ShowFullScreen )
253  // will update the state properly
254  setTopLevelMenuInternal( d->topLevel );
255  */
256  }
257  if( parentWidget() && obj == parentWidget() && ev->type() == QEvent::ParentChange )
258  {
259  KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
260  setVisible( parentWidget()->isTopLevel() || parentWidget()->isVisible());
261  }
262  if( parentWidget() && !parentWidget()->isTopLevel() && obj == parentWidget())
263  { // if the parent is not toplevel, KMenuBar needs to match its visibility status
264  if( ev->type() == QEvent::Show )
265  {
266  KWindowSystem::setMainWindow( this, parentWidget()->topLevelWidget()->winId());
267  show();
268  }
269  if( ev->type() == QEvent::Hide )
270  hide();
271  }
272  }
273  else
274  {
275  if( parentWidget() && obj == parentWidget()->topLevelWidget())
276  {
277  if( ev->type() == QEvent::WindowStateChange
278  && !parentWidget()->topLevelWidget()->isFullScreen() )
279  setTopLevelMenuInternal( d->wasTopLevel );
280  }
281  }
282  return QMenuBar::eventFilter( obj, ev );
283 }
284 
285 
286 void KMenuBar::updateFallbackSize()
287 {
288  if( !d->topLevel )
289  return;
290 #ifdef Q_WS_X11
291  if( d->selection->owner() != None )
292 #endif
293  { // somebody is managing us, don't mess anything, undo changes
294  // done in fallback mode if needed
295  d->selection_timer.stop();
296  if( d->fallback_mode )
297  {
298  d->fallback_mode = false;
299  KWindowSystem::setStrut( winId(), 0, 0, 0, 0 );
300  setMinimumSize( 0, 0 );
301  setMaximumSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
302  updateMenuBarSize();
303  }
304  return;
305  }
306  if( d->selection_timer.isActive())
307  return;
308  d->selection_timer.setInterval(100);
309  d->selection_timer.setSingleShot(true);
310  d->selection_timer.start();
311 }
312 
313 void KMenuBar::selectionTimeout()
314 { // nobody is managing us, handle resizing
315  if ( d->topLevel )
316  {
317  d->fallback_mode = true; // KMenuBar is handling its position itself
318  KConfigGroup xineramaConfig(KGlobal::config(),"Xinerama");
319  int screen = xineramaConfig.readEntry("MenubarScreen",
320  QApplication::desktop()->screenNumber(QPoint(0,0)) );
321  QRect area = QApplication::desktop()->screenGeometry(screen);
322  int margin = 0;
323  move(area.left() - margin, area.top() - margin);
324  setFixedSize(area.width() + 2* margin , heightForWidth( area.width() + 2 * margin ) );
325 #ifdef Q_WS_X11
326  int strut_height = height() - margin;
327  if( strut_height < 0 )
328  strut_height = 0;
329  KWindowSystem::setStrut( winId(), 0, 0, strut_height, 0 );
330 #endif
331  }
332 }
333 
334 void KMenuBar::resizeEvent( QResizeEvent *e )
335 {
336  if( e->spontaneous() && d->topLevel && !d->fallback_mode )
337  {
338  ++block_resize; // do not respond with configure request to ConfigureNotify event
339  QMenuBar::resizeEvent(e); // to avoid possible infinite loop
340  --block_resize;
341  }
342  else
343  QMenuBar::resizeEvent(e);
344 }
345 
346 void KMenuBar::setGeometry( const QRect& r )
347 {
348  setGeometry( r.x(), r.y(), r.width(), r.height() );
349 }
350 
351 void KMenuBar::setGeometry( int x, int y, int w, int h )
352 {
353  if( block_resize > 0 )
354  {
355  move( x, y );
356  return;
357  }
358  checkSize( w, h );
359  if( geometry() != QRect( x, y, w, h ))
360  QMenuBar::setGeometry( x, y, w, h );
361 }
362 
363 void KMenuBar::resize( int w, int h )
364 {
365  if( block_resize > 0 )
366  return;
367  checkSize( w, h );
368  if( size() != QSize( w, h ))
369  QMenuBar::resize( w, h );
370 // kDebug() << "RS:" << w << ":" << h << ":" << width() << ":" << height() << ":" << minimumWidth() << ":" << minimumHeight();
371 }
372 
373 void KMenuBar::resize( const QSize& s )
374 {
375  QMenuBar::resize( s );
376 }
377 
378 void KMenuBar::checkSize( int& w, int& h )
379 {
380  if( !d->topLevel || d->fallback_mode )
381  return;
382  QSize s = sizeHint();
383  w = s.width();
384  h = s.height();
385  // This is not done as setMinimumSize(), because that would set the minimum
386  // size in WM_NORMAL_HINTS, and KWin would not allow changing to smaller size
387  // anymore
388  w = qMax( w, d->min_size.width());
389  h = qMax( h, d->min_size.height());
390 }
391 
392 // QMenuBar's sizeHint() gives wrong size (insufficient width), which causes wrapping in the kicker applet
393 QSize KMenuBar::sizeHint() const
394 {
395  if( !d->topLevel || block_resize > 0 )
396  return QMenuBar::sizeHint();
397  // Since QMenuBar::sizeHint() may indirectly call resize(),
398  // avoid infinite recursion.
399  ++block_resize;
400  // find the minimum useful height, and enlarge the width until the menu fits in that height (one row)
401  int h = heightForWidth( 1000000 );
402  int w = QMenuBar::sizeHint().width();
403  // optimization - don't call heightForWidth() too many times
404  while( heightForWidth( w + 12 ) > h )
405  w += 12;
406  while( heightForWidth( w + 4 ) > h )
407  w += 4;
408  while( heightForWidth( w ) > h )
409  ++w;
410  --block_resize;
411  return QSize( w, h );
412 }
413 
414 #ifdef Q_WS_X11
415 bool KMenuBar::x11Event( XEvent* ev )
416 {
417  if( ev->type == ClientMessage && ev->xclient.message_type == msg_type_atom
418  && ev->xclient.window == winId())
419  {
420  // QMenuBar is trying really hard to keep the size it deems right.
421  // Forcing minimum size and blocking resizing to match parent size
422  // in checkResizingToParent() seem to be the only way to make
423  // KMenuBar keep the size it wants
424  d->min_size = QSize( ev->xclient.data.l[ 1 ], ev->xclient.data.l[ 2 ] );
425 // kDebug() << "MINSIZE:" << d->min_size;
426  updateMenuBarSize();
427  return true;
428  }
429  return QMenuBar::x11Event( ev );
430 }
431 #endif
432 
433 void KMenuBar::updateMenuBarSize()
434  {
435  //menuContentsChanged(); // trigger invalidating calculated size
436  resize( sizeHint()); // and resize to preferred size
437  }
438 
439 void KMenuBar::setFrameStyle( int style )
440 {
441  if( d->topLevel )
442  d->frameStyle = style;
443 // else
444 // QMenuBar::setFrameStyle( style );
445 }
446 
447 void KMenuBar::setLineWidth( int width )
448 {
449  if( d->topLevel )
450  d->lineWidth = width;
451 // else
452 // QMenuBar::setLineWidth( width );
453 }
454 
455 void KMenuBar::setMargin( int margin )
456 {
457  if( d->topLevel )
458  d->margin = margin;
459 // else
460 // QMenuBar::setMargin( margin );
461 }
462 
463 void KMenuBar::closeEvent( QCloseEvent* e )
464 {
465  if( d->topLevel )
466  e->ignore(); // mainly for the fallback mode
467  else
468  QMenuBar::closeEvent( e );
469 }
470 
471 void KMenuBar::paintEvent( QPaintEvent* pe )
472 {
473  // Closes the BR77113
474  // We need to overload this method to paint only the menu items
475  // This way when the KMenuBar is embedded in the menu applet it
476  // integrates correctly.
477  //
478  // Background mode and origin are set so late because of styles
479  // using the polish() method to modify these settings.
480  //
481  // Of course this hack can safely be removed when real transparency
482  // will be available
483 
484 // if( !d->topLevel )
485  {
486  QMenuBar::paintEvent(pe);
487  }
488 #if 0
489  else
490  {
491  QPainter p(this);
492  bool up_enabled = isUpdatesEnabled();
493  Qt::BackgroundMode bg_mode = backgroundMode();
494  BackgroundOrigin bg_origin = backgroundOrigin();
495 
496  setUpdatesEnabled(false);
497  setBackgroundMode(Qt::X11ParentRelative);
498  setBackgroundOrigin(WindowOrigin);
499 
500  p.eraseRect( rect() );
501  erase();
502 
503  QColorGroup g = colorGroup();
504  bool e;
505 
506  for ( int i=0; i<(int)count(); i++ )
507  {
508  QMenuItem *mi = findItem( idAt( i ) );
509 
510  if ( !mi->text().isEmpty() || !mi->icon().isNull() )
511  {
512  QRect r = itemRect(i);
513  if(r.isEmpty() || !mi->isVisible())
514  continue;
515 
516  e = mi->isEnabled() && mi->isVisible();
517  if ( e )
518  g = isEnabled() ? ( isActiveWindow() ? palette().active() :
519  palette().inactive() ) : palette().disabled();
520  else
521  g = palette().disabled();
522 
523  bool item_active = ( activeAction() == mi );
524 
525  p.setClipRect(r);
526 
527  if( item_active )
528  {
529  QStyleOptionMenuItem miOpt;
530  miOpt.init(this);
531  miOpt.rect = r;
532  miOpt.text = mi->text();
533  miOpt.icon = mi->icon();
534  miOpt.palette = g;
535 
536  QStyle::State flags = QStyle::State_None;
537  if (isEnabled() && e)
538  flags |= QStyle::State_Enabled;
539  if ( item_active )
540  flags |= QStyle::State_Active;
541  if ( item_active && actItemDown )
542  flags |= QStyle::State_Down;
543  flags |= QStyle::State_HasFocus;
544 
545  mi->state = flags;
546 
547 
548  style()->drawControl(QStyle::CE_MenuBarItem, &miOpt, &p, this);
549  }
550  else
551  {
552  style()->drawItem(p, r, Qt::AlignCenter | Qt::AlignVCenter | Qt::TextShowMnemonic,
553  g, e, mi->pixmap(), mi->text());
554  }
555  }
556  }
557 
558  setBackgroundOrigin(bg_origin);
559  setBackgroundMode(bg_mode);
560  setUpdatesEnabled(up_enabled);
561  }
562 #endif
563 }
564 
565 #include "kmenubar.moc"
Atom
unsigned long Atom
Definition: kapplication.h:29
NET::TopMenu
indicates a toplevel menu (AKA macmenu).
Definition: netwm_def.h:345
block_resize
static int block_resize
Definition: kmenubar.cpp:68
msg_type_atom
static Atom msg_type_atom
Definition: kmenubar.cpp:108
KMenuBar::setTopLevelMenu
void setTopLevelMenu(bool top_level=true)
This controls whether or not this menubar will be a top-level bar similar to the way Macintosh handle...
Definition: kmenubar.cpp:155
kdebug.h
kapplication.h
initAtoms
static void initAtoms()
Definition: kmenubar.cpp:111
kglobalsettings.h
KMenuBar::paintEvent
virtual void paintEvent(QPaintEvent *)
Definition: kmenubar.cpp:471
KMenuBar::setGeometry
virtual void setGeometry(const QRect &r)
Definition: kmenubar.cpp:346
KMenuBar::slotReadConfig
void slotReadConfig()
Definition: kmenubar.cpp:230
timeout
int timeout
kconfig.h
QWidget
KMenuBar::setLineWidth
virtual void setLineWidth(int)
Definition: kmenubar.cpp:447
KMenuBar::~KMenuBar
~KMenuBar()
Definition: kmenubar.cpp:150
KGlobalSettings::self
static KGlobalSettings * self()
Return the KGlobalSettings singleton.
Definition: kglobalsettings.cpp:188
KWindowSystem::setType
static void setType(WId win, NET::WindowType windowType)
Sets the type of window win to windowType.
Definition: kwindowsystem_mac.cpp:473
QObject
KMenuBar::isTopLevelMenu
bool isTopLevelMenu() const
Is our menubar a top-level (Macintosh style) menubar?
Definition: kmenubar.cpp:224
KGlobal::config
KSharedConfigPtr config()
None
kglobal.h
KSelectionWatcher
This class implements watching manager selections, as described in the ICCCM section 2...
Definition: kmanagerselection.h:155
KMenuBar::KMenuBar
KMenuBar(QWidget *parent=0)
Definition: kmenubar.cpp:135
KMenuBar::sizeHint
virtual QSize sizeHint() const
Definition: kmenubar.cpp:393
kmenubar.h
KWindowSystem::setStrut
static void setStrut(WId win, int left, int right, int top, int bottom)
Convenience function for setExtendedStrut() that automatically makes struts as wide/high as the scree...
Definition: kwindowsystem_mac.cpp:591
kmanagerselection.h
KMenuBar::resize
virtual void resize(int w, int h)
Definition: kmenubar.cpp:363
KMenuBar::resizeEvent
virtual void resizeEvent(QResizeEvent *)
Definition: kmenubar.cpp:334
KMenuBar::setFrameStyle
virtual void setFrameStyle(int)
Definition: kmenubar.cpp:439
KWindowSystem::setMainWindow
static void setMainWindow(QWidget *subwindow, WId mainwindow)
Sets the parent window of subwindow to be mainwindow.
Definition: kwindowsystem_mac.cpp:412
QMenuBar
KMenuBar::eventFilter
virtual bool eventFilter(QObject *, QEvent *)
Definition: kmenubar.cpp:236
KConfigGroup
KMenuBar::closeEvent
virtual void closeEvent(QCloseEvent *)
Definition: kmenubar.cpp:463
QPoint
QRect
kwindowsystem.h
QSize
KMenuBar::x11Event
virtual bool x11Event(XEvent *)
Definition: kmenubar.cpp:415
selection_atom
static Atom selection_atom
Definition: kmenubar.cpp:107
KConfigGroup::readEntry
T readEntry(const QString &key, const T &aDefault) const
KMenuBar::setMargin
virtual void setMargin(int)
Definition: kmenubar.cpp:455
kconfiggroup.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:15 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal