Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / vcl / unx / kde4 / KDESalGraphics.cxx
blob173479622103b9b94a231921adb54a286e1db3bc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #define Region QtXRegion
22 #include <QStyle>
23 #include <QStyleOption>
24 #include <QPainter>
25 #include <QFrame>
26 #include <QLabel>
28 #include <kapplication.h>
29 #include <kdebug.h>
31 #undef Region
33 #include "KDESalGraphics.hxx"
34 #include "KDESalInstance.hxx"
36 #include <vcl/settings.hxx>
37 #include <vcl/decoview.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <unx/saldata.hxx>
41 using namespace ::rtl;
43 /**
44 Conversion function between VCL ControlState together with
45 ImplControlValue and Qt state flags.
46 @param nControlState State of the widget (default, focused, ...) in Native Widget Framework.
47 @param aValue Value held by the widget (on, off, ...)
49 QStyle::State vclStateValue2StateFlag( ControlState nControlState,
50 const ImplControlValue& aValue )
52 QStyle::State nState =
53 ( (nControlState & CTRL_STATE_DEFAULT)? QStyle::State_None: QStyle::State_None ) |
54 ( (nControlState & CTRL_STATE_ENABLED)? QStyle::State_Enabled: QStyle::State_None ) |
55 ( (nControlState & CTRL_STATE_FOCUSED)? QStyle::State_HasFocus: QStyle::State_None ) |
56 ( (nControlState & CTRL_STATE_PRESSED)? QStyle::State_Sunken: QStyle::State_None ) |
57 ( (nControlState & CTRL_STATE_SELECTED)? QStyle::State_Selected : QStyle::State_None ) |
58 ( (nControlState & CTRL_STATE_ROLLOVER)? QStyle::State_MouseOver: QStyle::State_None );
59 //TODO ( (nControlState & CTRL_STATE_HIDDEN)? QStyle::State_: QStyle::State_None ) |
61 switch ( aValue.getTristateVal() )
63 case BUTTONVALUE_ON: nState |= QStyle::State_On; break;
64 case BUTTONVALUE_OFF: nState |= QStyle::State_Off; break;
65 case BUTTONVALUE_MIXED: nState |= QStyle::State_NoChange; break;
66 default: break;
69 return nState;
72 /**
73 Convert VCL Rectangle to QRect.
74 @param rControlRegion The Rectangle to convert.
75 @return The matching QRect
77 QRect region2QRect( const Rectangle& rControlRegion )
79 return QRect(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.GetWidth(), rControlRegion.GetHeight());
82 KDESalGraphics::KDESalGraphics() :
83 m_image(NULL)
87 KDESalGraphics::~KDESalGraphics()
89 if (m_image)
90 delete m_image;
93 bool KDESalGraphics::IsNativeControlSupported( ControlType type, ControlPart part )
95 if (type == CTRL_PUSHBUTTON) return true;
97 if (type == CTRL_MENUBAR) return true;
99 if (type == CTRL_MENU_POPUP) return true;
101 if (type == CTRL_EDITBOX) return true;
103 if (type == CTRL_COMBOBOX) return true;
105 if (type == CTRL_TOOLBAR) return true;
107 if (type == CTRL_CHECKBOX) return true;
109 if (type == CTRL_LISTBOX) return true;
111 if (type == CTRL_LISTNODE) return true;
113 if (type == CTRL_FRAME) return true;
115 if (type == CTRL_SCROLLBAR) return true;
117 if (type == CTRL_WINDOW_BACKGROUND) return true;
119 if (type == CTRL_SPINBOX && (part == PART_ENTIRE_CONTROL || part == HAS_BACKGROUND_TEXTURE) ) return true;
121 // no spinbuttons for KDE, paint spinbox complete
122 //if (type == CTRL_SPINBUTTONS) return true;
124 if (type == CTRL_GROUPBOX) return true;
126 if (type == CTRL_FIXEDLINE) return true;
128 if (type == CTRL_TOOLTIP) return true;
130 if (type == CTRL_RADIOBUTTON) return true;
132 if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA) )
133 return true;
135 if ( (type == CTRL_PROGRESS) && (part == PART_ENTIRE_CONTROL) ) return true;
137 return false;
140 /// helper drawing methods
141 namespace
143 void draw( QStyle::ControlElement element, QStyleOption* option, QImage* image, QStyle::State state, QRect rect = QRect())
145 option->state |= state;
146 option->rect = !rect.isNull() ? rect : image->rect();
148 QPainter painter(image);
149 kapp->style()->drawControl(element, option, &painter);
152 void draw( QStyle::PrimitiveElement element, QStyleOption* option, QImage* image, QStyle::State state, QRect rect = QRect())
154 option->state |= state;
155 option->rect = !rect.isNull() ? rect : image->rect();
157 QPainter painter(image);
158 kapp->style()->drawPrimitive(element, option, &painter);
161 void draw( QStyle::ComplexControl element, QStyleOptionComplex* option, QImage* image, QStyle::State state )
163 option->state |= state;
164 option->rect = image->rect();
166 QPainter painter(image);
167 kapp->style()->drawComplexControl(element, option, &painter);
170 void lcl_drawFrame(QStyle::PrimitiveElement element, QImage* image, QStyle::State state)
172 #if ( QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 ) )
173 QStyleOptionFrameV3 option;
174 option.frameShape = QFrame::StyledPanel;
175 option.state = QStyle::State_Sunken;
176 #else
177 QStyleOptionFrame option;
179 QFrame aFrame( NULL );
180 aFrame.setFrameRect( QRect(0, 0, image->width(), image->height()) );
181 aFrame.setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
182 aFrame.ensurePolished();
184 option.initFrom( &aFrame );
185 option.lineWidth = aFrame.lineWidth();
186 option.midLineWidth = aFrame.midLineWidth();
187 #endif
189 draw(element, &option, image, state);
193 #if QT_VERSION >= QT_VERSION_CHECK( 4, 5, 0 )
194 #define IMAGE_BASED_PAINTING
195 #else
196 #undef IMAGE_BASED_PAINTING
197 #endif
199 #ifdef IMAGE_BASED_PAINTING
200 // There is a small catch with this function, although hopefully only philosophical.
201 // Officially Xlib's Region is an opaque data type, with only functions for manipulating it.
202 // However, whoever designed it apparently didn't give it that much thought, as it's impossible
203 // to find out what exactly a region actually is (except for really weird ways like XClipBox()
204 // and repeated XPointInRegion(), which would be awfully slow). Fortunately, the header file
205 // describing the structure actually happens to be installed too, and there's at least one
206 // widely used software using it (Compiz). So access the data directly too and assume that
207 // everybody who compiles with Qt4 support has Xlib new enough and good enough to support this.
208 // In case this doesn't work for somebody, try #include <X11/region.h> instead, or build
209 // without IMAGE_BASED_PAINTING (in which case QApplication::setGraphicsSystem( "native" ) may
210 // be needed too).
211 #include <X11/Xregion.h>
212 static QRegion XRegionToQRegion( XLIB_Region xr )
214 QRegion qr;
215 for( int i = 0;
216 i < xr->numRects;
217 ++i )
219 BOX& b = xr->rects[ i ];
220 qr |= QRect( b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1 ); // x2,y2 is outside, not the bottom-right corner
222 return qr;
224 #endif
226 bool KDESalGraphics::drawNativeControl( ControlType type, ControlPart part,
227 const Rectangle& rControlRegion, ControlState nControlState,
228 const ImplControlValue& value,
229 const OUString& )
231 if( lastPopupRect.isValid() && ( type != CTRL_MENU_POPUP || part != PART_MENU_ITEM ))
232 lastPopupRect = QRect();
234 // put not implemented types here
235 if (type == CTRL_SPINBUTTONS)
237 return false;
240 bool returnVal = true;
242 QRect widgetRect = region2QRect(rControlRegion);
243 if( type == CTRL_SPINBOX && part == PART_ALL_BUTTONS )
244 type = CTRL_SPINBUTTONS;
245 if( type == CTRL_SPINBUTTONS )
247 OSL_ASSERT( value.getType() != CTRL_SPINBUTTONS );
248 const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue *>(&value);
249 Rectangle aButtonRect( pSpinVal->maUpperRect);
250 aButtonRect.Union( pSpinVal->maLowerRect );
251 widgetRect = QRect( aButtonRect.Left(), aButtonRect.Top(),
252 aButtonRect.Right(), aButtonRect.Bottom() );
255 //if no image, or resized, make a new image
256 if (!m_image || m_image->size() != widgetRect.size())
258 if (m_image)
259 delete m_image;
261 m_image = new QImage( widgetRect.width(),
262 widgetRect.height(),
263 QImage::Format_ARGB32 );
265 m_image->fill(KApplication::palette().color(QPalette::Window).rgb());
267 QRegion* clipRegion = NULL;
269 if (type == CTRL_PUSHBUTTON)
271 m_image->fill( Qt::transparent );
272 QStyleOptionButton option;
273 draw( QStyle::CE_PushButton, &option, m_image,
274 vclStateValue2StateFlag(nControlState, value) );
276 else if (type == CTRL_MENUBAR)
278 if (part == PART_MENU_ITEM)
280 QStyleOptionMenuItem option;
281 if ( ( nControlState & CTRL_STATE_ROLLOVER )
282 && kapp->style()->styleHint( QStyle::SH_MenuBar_MouseTracking ) )
283 option.state |= QStyle::State_Selected;
285 if ( nControlState & CTRL_STATE_SELECTED ) // Passing State_Sunken is currently not documented.
286 option.state |= QStyle::State_Sunken; // But some kinds of QStyle interpret it.
288 draw( QStyle::CE_MenuBarItem, &option, m_image,
289 vclStateValue2StateFlag(nControlState, value) );
291 else if (part == PART_ENTIRE_CONTROL)
293 QStyleOptionMenuItem option;
294 draw( QStyle::CE_MenuBarEmptyArea, &option, m_image,
295 vclStateValue2StateFlag(nControlState, value) );
297 else
299 returnVal = false;
302 else if (type == CTRL_MENU_POPUP)
304 OSL_ASSERT( part == PART_MENU_ITEM ? lastPopupRect.isValid() : !lastPopupRect.isValid());
305 if( part == PART_MENU_ITEM )
307 QStyleOptionMenuItem option;
308 draw( QStyle::CE_MenuItem, &option, m_image,
309 vclStateValue2StateFlag(nControlState, value) );
310 // HACK: LO core first paints the entire popup and only then it paints menu items,
311 // but QMenu::paintEvent() paints popup frame after all items. That means highlighted
312 // items here would paint the highlight over the frame border. Since calls to PART_MENU_ITEM
313 // are always preceded by calls to PART_ENTIRE_CONTROL, just remember the size for the whole
314 // popup (otherwise not possible to get here) and draw the border afterwards.
315 QRect framerect( lastPopupRect.topLeft() - widgetRect.topLeft(),
316 widgetRect.size().expandedTo( lastPopupRect.size()));
317 QStyleOptionFrame frame;
318 draw( QStyle::PE_FrameMenu, &frame, m_image, vclStateValue2StateFlag( nControlState, value ), framerect );
320 else if( part == PART_MENU_SEPARATOR )
322 QStyleOptionMenuItem option;
323 option.menuItemType = QStyleOptionMenuItem::Separator;
324 // Painting the whole menu item area results in different background
325 // with at least Plastique style, so clip only to the separator itself
326 // (QSize( 2, 2 ) is hardcoded in Qt)
327 option.rect = m_image->rect();
328 QSize size = kapp->style()->sizeFromContents( QStyle::CT_MenuItem, &option, QSize( 2, 2 ));
329 QRect rect = m_image->rect();
330 QPoint center = rect.center();
331 rect.setHeight( size.height());
332 rect.moveCenter( center );
333 // don't paint over popup frame border (like the hack above, but here it can be simpler)
334 int fw = kapp->style()->pixelMetric( QStyle::PM_MenuPanelWidth );
335 clipRegion = new QRegion( rect.translated( widgetRect.topLeft()).adjusted( fw, 0, -fw, 0 ));
336 draw( QStyle::CE_MenuItem, &option, m_image,
337 vclStateValue2StateFlag(nControlState, value), rect );
339 else if( part == PART_MENU_ITEM_CHECK_MARK || part == PART_MENU_ITEM_RADIO_MARK )
341 QStyleOptionMenuItem option;
342 option.checkType = ( part == PART_MENU_ITEM_CHECK_MARK )
343 ? QStyleOptionMenuItem::NonExclusive : QStyleOptionMenuItem::Exclusive;
344 option.checked = ( nControlState & CTRL_STATE_PRESSED );
345 // widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt
346 // paints the whole menu item, so translate position (and it'll be clipped);
347 // it is also necessary to fill the background transparently first, as this
348 // is painted after menuitem highlight, otherwise there would be a grey area
349 assert( value.getType() == CTRL_MENU_POPUP );
350 const MenupopupValue* menuVal = static_cast<const MenupopupValue*>(&value);
351 QRect menuItemRect( region2QRect( menuVal->maItemRect ));
352 QRect rect( menuItemRect.topLeft() - widgetRect.topLeft(),
353 widgetRect.size().expandedTo( menuItemRect.size()));
354 m_image->fill( Qt::transparent );
355 draw( QStyle::CE_MenuItem, &option, m_image,
356 vclStateValue2StateFlag(nControlState, value), rect );
358 else if( part == PART_ENTIRE_CONTROL )
360 QStyleOptionMenuItem option;
361 draw( QStyle::PE_PanelMenu, &option, m_image, vclStateValue2StateFlag( nControlState, value ));
362 // Try hard to get any frame!
363 QStyleOptionFrame frame;
364 draw( QStyle::PE_FrameMenu, &frame, m_image, vclStateValue2StateFlag( nControlState, value ));
365 draw( QStyle::PE_FrameWindow, &frame, m_image, vclStateValue2StateFlag( nControlState, value ));
366 lastPopupRect = widgetRect;
368 else
369 returnVal = false;
371 else if ( (type == CTRL_TOOLBAR) && (part == PART_BUTTON) )
373 m_image->fill( Qt::transparent );
374 QStyleOptionToolButton option;
376 option.arrowType = Qt::NoArrow;
377 option.subControls = QStyle::SC_ToolButton;
379 option.state = vclStateValue2StateFlag( nControlState, value );
380 option.state |= QStyle::State_Raised | QStyle::State_Enabled | QStyle::State_AutoRaise;
382 draw( QStyle::CC_ToolButton, &option, m_image,
383 vclStateValue2StateFlag(nControlState, value) );
385 else if ( (type == CTRL_TOOLBAR) && (part == PART_ENTIRE_CONTROL) )
387 QStyleOptionToolBar option;
389 option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
390 option.state = vclStateValue2StateFlag( nControlState, value );
392 draw( QStyle::CE_ToolBar, &option, m_image,
393 vclStateValue2StateFlag(nControlState, value) );
395 else if ( (type == CTRL_TOOLBAR) && (part == PART_THUMB_VERT) )
396 { // reduce paint area only to the handle area
397 const int width = kapp->style()->pixelMetric(QStyle::PM_ToolBarHandleExtent);
398 QRect rect( 0, 0, width, widgetRect.height());
399 clipRegion = new QRegion( widgetRect.x(), widgetRect.y(), width, widgetRect.height());
401 QStyleOption option;
402 option.state = QStyle::State_Horizontal;
404 draw( QStyle::PE_IndicatorToolBarHandle, &option, m_image,
405 vclStateValue2StateFlag(nControlState, value), rect );
407 else if (type == CTRL_EDITBOX)
409 QStyleOptionFrameV2 option;
410 draw( QStyle::PE_PanelLineEdit, &option, m_image,
411 vclStateValue2StateFlag(nControlState, value), m_image->rect().adjusted( 2, 2, -2, -2 ));
413 draw( QStyle::PE_FrameLineEdit, &option, m_image,
414 vclStateValue2StateFlag(nControlState, value));
416 else if (type == CTRL_COMBOBOX)
418 QStyleOptionComboBox option;
419 option.editable = true;
421 draw( QStyle::CC_ComboBox, &option, m_image,
422 vclStateValue2StateFlag(nControlState, value) );
424 else if (type == CTRL_LISTBOX)
426 if( part == PART_WINDOW )
428 lcl_drawFrame( QStyle::PE_Frame, m_image,
429 vclStateValue2StateFlag(nControlState, value) );
431 else
433 QStyleOptionComboBox option;
434 if (part == PART_SUB_EDIT)
436 draw( QStyle::CE_ComboBoxLabel, &option, m_image,
437 vclStateValue2StateFlag(nControlState, value) );
439 else
441 draw( QStyle::CC_ComboBox, &option, m_image,
442 vclStateValue2StateFlag(nControlState, value) );
446 else if (type == CTRL_LISTNODE)
448 m_image->fill( Qt::transparent );
449 QStyleOption option;
450 option.state = QStyle::State_Item | QStyle::State_Children;
452 if (value.getTristateVal() == BUTTONVALUE_ON)
453 option.state |= QStyle::State_Open;
455 draw( QStyle::PE_IndicatorBranch, &option, m_image,
456 vclStateValue2StateFlag(nControlState, value) );
458 else if (type == CTRL_CHECKBOX)
460 m_image->fill( Qt::transparent );
461 QStyleOptionButton option;
462 draw( QStyle::CE_CheckBox, &option, m_image,
463 vclStateValue2StateFlag(nControlState, value) );
465 else if (type == CTRL_SCROLLBAR)
467 if ((part == PART_DRAW_BACKGROUND_VERT) || (part == PART_DRAW_BACKGROUND_HORZ))
469 QStyleOptionSlider option;
470 OSL_ASSERT( value.getType() == CTRL_SCROLLBAR );
471 const ScrollbarValue* sbVal = static_cast<const ScrollbarValue *>(&value);
473 //if the scroll bar is active (aka not degenrate...allow for hover events
474 if (sbVal->mnVisibleSize < sbVal->mnMax)
475 option.state = QStyle::State_MouseOver;
477 bool horizontal = ( part == PART_DRAW_BACKGROUND_HORZ ); //horizontal or vertical
478 option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
479 if( horizontal )
480 option.state |= QStyle::State_Horizontal;
482 //setup parameters from the OO values
483 option.minimum = sbVal->mnMin;
484 option.maximum = sbVal->mnMax - sbVal->mnVisibleSize;
485 option.maximum = qMax( option.maximum, option.minimum ); // bnc#619772
486 option.sliderValue = sbVal->mnCur;
487 option.sliderPosition = sbVal->mnCur;
488 option.pageStep = sbVal->mnVisibleSize;
490 //setup the active control...always the slider
491 if (sbVal->mnThumbState & CTRL_STATE_ROLLOVER)
492 option.activeSubControls = QStyle::SC_ScrollBarSlider;
494 draw( QStyle::CC_ScrollBar, &option, m_image,
495 vclStateValue2StateFlag(nControlState, value) );
497 else
499 returnVal = false;
502 else if (type == CTRL_SPINBOX)
504 QStyleOptionSpinBox option;
506 // determine active control
507 if( value.getType() == CTRL_SPINBUTTONS )
509 const SpinbuttonValue* pSpinVal = static_cast<const SpinbuttonValue *>(&value);
510 if( (pSpinVal->mnUpperState & CTRL_STATE_PRESSED) )
511 option.activeSubControls |= QStyle::SC_SpinBoxUp;
512 if( (pSpinVal->mnLowerState & CTRL_STATE_PRESSED) )
513 option.activeSubControls |= QStyle::SC_SpinBoxDown;
516 draw( QStyle::CC_SpinBox, &option, m_image,
517 vclStateValue2StateFlag(nControlState, value) );
519 else if (type == CTRL_GROUPBOX)
521 QStyleOptionGroupBox option;
522 draw( QStyle::CC_GroupBox, &option, m_image,
523 vclStateValue2StateFlag(nControlState, value) );
525 else if (type == CTRL_RADIOBUTTON)
527 m_image->fill( Qt::transparent );
528 QStyleOptionButton option;
529 draw( QStyle::CE_RadioButton, &option, m_image,
530 vclStateValue2StateFlag(nControlState, value) );
532 else if (type == CTRL_TOOLTIP)
534 QStyleOption option;
535 draw( QStyle::PE_PanelTipLabel, &option, m_image,
536 vclStateValue2StateFlag(nControlState, value) );
538 else if (type == CTRL_FRAME)
540 lcl_drawFrame( QStyle::PE_Frame, m_image,
541 vclStateValue2StateFlag(nControlState, value) );
543 // draw just the border, see http://qa.openoffice.org/issues/show_bug.cgi?id=107945
544 int fw = static_cast< KDESalInstance* >(GetSalData()->m_pInstance)->getFrameWidth();
545 clipRegion = new QRegion( QRegion( widgetRect ).subtracted( widgetRect.adjusted( fw, fw, -fw, -fw )));
547 else if (type == CTRL_WINDOW_BACKGROUND)
549 m_image->fill(KApplication::palette().color(QPalette::Window).rgb());
551 else if (type == CTRL_FIXEDLINE)
553 QStyleOptionMenuItem option;
554 option.menuItemType = QStyleOptionMenuItem::Separator;
555 option.state |= QStyle::State_Item;
557 draw( QStyle::CE_MenuItem, &option, m_image,
558 vclStateValue2StateFlag(nControlState, value) );
560 else if (type == CTRL_SLIDER && (part == PART_TRACK_HORZ_AREA || part == PART_TRACK_VERT_AREA))
562 OSL_ASSERT( value.getType() == CTRL_SLIDER );
563 const SliderValue* slVal = static_cast<const SliderValue *>(&value);
564 QStyleOptionSlider option;
566 option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
567 option.state = vclStateValue2StateFlag( nControlState, value );
568 option.maximum = slVal->mnMax;
569 option.minimum = slVal->mnMin;
570 option.sliderPosition = option.sliderValue = slVal->mnCur;
571 bool horizontal = ( part == PART_TRACK_HORZ_AREA ); //horizontal or vertical
572 option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
573 if( horizontal )
574 option.state |= QStyle::State_Horizontal;
576 draw( QStyle::CC_Slider, &option, m_image, vclStateValue2StateFlag(nControlState, value) );
578 else if( type == CTRL_PROGRESS && part == PART_ENTIRE_CONTROL )
580 QStyleOptionProgressBarV2 option;
581 option.minimum = 0;
582 option.maximum = widgetRect.width();
583 option.progress = value.getNumericVal();
584 option.rect = QRect(0, 0, widgetRect.width(), widgetRect.height());
585 option.state = vclStateValue2StateFlag( nControlState, value );
587 draw( QStyle::CE_ProgressBar, &option, m_image,
588 vclStateValue2StateFlag(nControlState, value) );
590 else
592 returnVal = false;
595 if (returnVal)
597 #ifdef IMAGE_BASED_PAINTING
598 // Create a wrapper QPixmap around the destination pixmap, allowing the use of QPainter.
599 // Using X11SalGraphics::CopyScreenArea() would require using QPixmap and if Qt uses
600 // other graphics system than native, QPixmap::handle() would be 0 (i.e. it wouldn't work),
601 // I have no idea how to create QPixmap with non-null handle() in such case, so go this way.
602 // See XRegionToQRegion() comment for a small catch (although not real hopefully).
603 QPixmap destPixmap = QPixmap::fromX11Pixmap( GetDrawable(), QPixmap::ExplicitlyShared );
604 QPainter paint( &destPixmap );
605 if( clipRegion && mpClipRegion )
606 paint.setClipRegion( clipRegion->intersected( XRegionToQRegion( mpClipRegion )));
607 else if( clipRegion )
608 paint.setClipRegion( *clipRegion );
609 else if( mpClipRegion )
610 paint.setClipRegion( XRegionToQRegion( mpClipRegion ));
611 paint.drawImage( widgetRect.left(), widgetRect.top(), *m_image,
612 0, 0, widgetRect.width(), widgetRect.height(),
613 Qt::ColorOnly | Qt::OrderedDither | Qt::OrderedAlphaDither );
614 #else
615 GC gc = GetFontGC();
616 if( gc )
618 XLIB_Region pTempClipRegion = NULL;
619 if( clipRegion )
621 pTempClipRegion = XCreateRegion();
622 foreach( const QRect& r, clipRegion->rects())
624 XRectangle xr;
625 xr.x = r.x();
626 xr.y = r.y();
627 xr.width = r.width();
628 xr.height = r.height();
629 XUnionRectWithRegion( &xr, pTempClipRegion, pTempClipRegion );
631 if( mpClipRegion )
632 XIntersectRegion( pTempClipRegion, mpClipRegion, pTempClipRegion );
633 XSetRegion( GetXDisplay(), gc, pTempClipRegion );
635 QPixmap pixmap = QPixmap::fromImage(*m_image, Qt::ColorOnly | Qt::OrderedDither | Qt::OrderedAlphaDither);
636 X11SalGraphics::CopyScreenArea( GetXDisplay(),
637 pixmap.handle(), pixmap.x11Info().screen(), pixmap.x11Info().depth(),
638 GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
639 gc, 0, 0, widgetRect.width(), widgetRect.height(), widgetRect.left(), widgetRect.top());
641 if( pTempClipRegion )
643 if( mpClipRegion )
644 XSetRegion( GetXDisplay(), gc, mpClipRegion );
645 else
646 XSetClipMask( GetXDisplay(), gc, None );
647 XDestroyRegion( pTempClipRegion );
650 else
651 returnVal = false;
652 #endif
654 delete clipRegion;
655 return returnVal;
658 bool KDESalGraphics::getNativeControlRegion( ControlType type, ControlPart part,
659 const Rectangle& controlRegion, ControlState controlState,
660 const ImplControlValue& val,
661 const OUString&,
662 Rectangle &nativeBoundingRegion, Rectangle &nativeContentRegion )
664 bool retVal = false;
666 QRect boundingRect = region2QRect( controlRegion );
667 QRect contentRect = boundingRect;
668 QStyleOptionComplex styleOption;
670 switch ( type )
672 // Metrics of the push button
673 case CTRL_PUSHBUTTON:
674 if (part == PART_ENTIRE_CONTROL)
676 styleOption.state = vclStateValue2StateFlag(controlState, val);
678 if ( controlState & CTRL_STATE_DEFAULT )
680 int size = kapp->style()->pixelMetric(
681 QStyle::PM_ButtonDefaultIndicator, &styleOption );
683 boundingRect.adjust( -size, -size, size, size );
685 retVal = true;
688 break;
689 case CTRL_EDITBOX:
691 int nFontHeight = kapp->fontMetrics().height();
692 //int nFrameSize = kapp->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
693 int nLayoutTop = kapp->style()->pixelMetric(QStyle::PM_LayoutTopMargin);
694 int nLayoutBottom = kapp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin);
695 int nLayoutLeft = kapp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
696 int nLayoutRight = kapp->style()->pixelMetric(QStyle::PM_LayoutRightMargin);
698 int nMinHeight = (nFontHeight + nLayoutTop + nLayoutBottom);
699 if( boundingRect.height() < nMinHeight )
701 int delta = nMinHeight - boundingRect.height();
702 boundingRect.adjust( 0, 0, 0, delta );
704 contentRect = boundingRect;
705 contentRect.adjust( -nLayoutLeft+1, -nLayoutTop+1, nLayoutRight-1, nLayoutBottom-1 );
706 retVal = true;
708 break;
710 case CTRL_CHECKBOX:
711 if (part == PART_ENTIRE_CONTROL)
713 styleOption.state = vclStateValue2StateFlag(controlState, val);
715 contentRect.setWidth(kapp->style()->pixelMetric(
716 QStyle::PM_IndicatorWidth, &styleOption));
717 contentRect.setHeight(kapp->style()->pixelMetric(
718 QStyle::PM_IndicatorHeight, &styleOption));
720 contentRect.adjust(0, 0,
721 2 * kapp->style()->pixelMetric(
722 QStyle::PM_FocusFrameHMargin, &styleOption),
723 2 * kapp->style()->pixelMetric(
724 QStyle::PM_FocusFrameVMargin, &styleOption)
727 boundingRect = contentRect;
729 retVal = true;
731 break;
733 case CTRL_COMBOBOX:
734 case CTRL_LISTBOX:
736 QStyleOptionComboBox cbo;
738 cbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
739 cbo.state = vclStateValue2StateFlag(controlState, val);
741 switch ( part )
743 case PART_ENTIRE_CONTROL:
745 int size = kapp->style()->pixelMetric(QStyle::PM_ComboBoxFrameWidth) - 2;
747 // find out the minimum size that should be used
748 // assume contents is a text ling
749 int nHeight = kapp->fontMetrics().height();
750 QSize aContentSize( contentRect.width(), nHeight );
751 QSize aMinSize = kapp->style()->
752 sizeFromContents( QStyle::CT_ComboBox, &cbo, aContentSize );
753 if( aMinSize.height() > contentRect.height() )
754 contentRect.adjust( 0, 0, 0, aMinSize.height() - contentRect.height() );
755 boundingRect = contentRect;
756 // FIXME: why this difference between comboboxes and listboxes ?
757 // because a combobox has a sub edit and that is positioned
758 // inside the outer bordered control ?
759 if( type == CTRL_COMBOBOX )
760 contentRect.adjust(-size,-size,size,size);
761 retVal = true;
762 break;
764 case PART_BUTTON_DOWN:
765 contentRect = kapp->style()->subControlRect(
766 QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxArrow );
768 contentRect.translate( boundingRect.left(), boundingRect.top() );
770 retVal = true;
771 break;
772 case PART_SUB_EDIT:
773 contentRect = kapp->style()->subControlRect(
774 QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField );
776 contentRect.translate( boundingRect.left(), boundingRect.top() );
778 retVal = true;
779 break;
780 case PART_WINDOW:
781 retVal = true;
782 break;
784 break;
786 case CTRL_SPINBOX:
788 QStyleOptionSpinBox sbo;
790 sbo.rect = QRect(0, 0, contentRect.width(), contentRect.height());
791 sbo.state = vclStateValue2StateFlag(controlState, val);
793 switch ( part )
795 case PART_BUTTON_UP:
796 contentRect = kapp->style()->subControlRect(
797 QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp );
798 contentRect.translate( boundingRect.left(), boundingRect.top() );
799 retVal = true;
800 boundingRect = QRect();
801 break;
803 case PART_BUTTON_DOWN:
804 contentRect = kapp->style()->subControlRect(
805 QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown );
806 retVal = true;
807 contentRect.translate( boundingRect.left(), boundingRect.top() );
808 boundingRect = QRect();
809 break;
811 case PART_SUB_EDIT:
812 contentRect = kapp->style()->subControlRect(
813 QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField );
814 retVal = true;
815 contentRect.translate( boundingRect.left(), boundingRect.top() );
816 break;
817 default:
818 retVal = true;
820 break;
822 case CTRL_MENU_POPUP:
824 int h, w;
825 switch ( part ) {
826 case PART_MENU_ITEM_CHECK_MARK:
827 h = kapp->style()->pixelMetric(QStyle::PM_IndicatorHeight);
828 w = kapp->style()->pixelMetric(QStyle::PM_IndicatorWidth);
829 retVal = true;
830 break;
831 case PART_MENU_ITEM_RADIO_MARK:
832 h = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight);
833 w = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth);
834 retVal = true;
835 break;
837 if (retVal) {
838 contentRect = QRect(0, 0, w, h);
839 boundingRect = contentRect;
841 break;
843 case CTRL_FRAME:
845 if( part == PART_BORDER )
847 int nFrameWidth = static_cast< KDESalInstance* >(GetSalData()->m_pInstance)->getFrameWidth();
848 sal_uInt16 nStyle = val.getNumericVal();
849 if( nStyle & FRAME_DRAW_NODRAW )
851 // in this case the question is: how thick would a frame be
852 // see brdwin.cxx, decoview.cxx
853 // most probably the behavior in decoview.cxx is wrong.
854 contentRect.adjust(nFrameWidth, nFrameWidth, -nFrameWidth, -nFrameWidth);
856 retVal = true;
858 break;
860 case CTRL_RADIOBUTTON:
862 const int h = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorHeight);
863 const int w = kapp->style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth);
865 contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h);
866 contentRect.adjust(0, 0,
867 2 * kapp->style()->pixelMetric(
868 QStyle::PM_FocusFrameHMargin, &styleOption),
869 2 * kapp->style()->pixelMetric(
870 QStyle::PM_FocusFrameVMargin, &styleOption)
872 boundingRect = contentRect;
874 retVal = true;
875 break;
877 case CTRL_SLIDER:
879 const int w = kapp->style()->pixelMetric(QStyle::PM_SliderLength);
880 if( part == PART_THUMB_HORZ )
882 contentRect = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height());
883 boundingRect = contentRect;
884 retVal = true;
886 else if( part == PART_THUMB_VERT )
888 contentRect = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w);
889 boundingRect = contentRect;
890 retVal = true;
892 break;
894 case CTRL_SCROLLBAR:
896 // core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(),
897 // for the rest also provide the track area (i.e. area not taken by buttons)
898 if( part == PART_TRACK_VERT_AREA || part == PART_TRACK_HORZ_AREA )
900 QStyleOptionSlider option;
901 bool horizontal = ( part == PART_TRACK_HORZ_AREA ); //horizontal or vertical
902 option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical;
903 if( horizontal )
904 option.state |= QStyle::State_Horizontal;
905 // getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper
906 // subclass), so use random sensible values (doesn't matter anyway, as the wanted
907 // geometry here depends only on button sizes)
908 option.maximum = 10;
909 option.minimum = 0;
910 option.sliderPosition = option.sliderValue = 4;
911 option.pageStep = 2;
912 // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
913 // widget and screen coordinates the same. QStyle functions should use screen
914 // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
915 // and sometimes uses widget coordinates.
916 QRect rect = contentRect;
917 rect.moveTo( 0, 0 );
918 option.rect = rect;
919 rect = kapp->style()->subControlRect( QStyle::CC_ScrollBar, &option,
920 QStyle::SC_ScrollBarGroove );
921 rect.translate( contentRect.topLeft()); // reverse the workaround above
922 contentRect = boundingRect = rect;
923 retVal = true;
926 default:
927 break;
929 if (retVal)
931 // Bounding region
932 Point aBPoint( boundingRect.x(), boundingRect.y() );
933 Size aBSize( boundingRect.width(), boundingRect.height() );
934 nativeBoundingRegion = Rectangle( aBPoint, aBSize );
936 // Region of the content
937 Point aPoint( contentRect.x(), contentRect.y() );
938 Size aSize( contentRect.width(), contentRect.height() );
939 nativeContentRegion = Rectangle( aPoint, aSize );
942 return retVal;
945 /** Test whether the position is in the native widget.
946 If the return value is TRUE, bIsInside contains information whether
947 aPos was or was not inside the native widget specified by the
948 nType/nPart combination.
950 bool KDESalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart,
951 const Rectangle& rControlRegion, const Point& rPos,
952 bool& rIsInside )
954 if ( nType == CTRL_SCROLLBAR )
956 if( nPart != PART_BUTTON_UP && nPart != PART_BUTTON_DOWN
957 && nPart != PART_BUTTON_LEFT && nPart != PART_BUTTON_RIGHT )
958 { // we adjust only for buttons (because some scrollbars have 3 buttons,
959 // and LO core doesn't handle such scrollbars well)
960 return FALSE;
962 rIsInside = FALSE;
963 bool bHorizontal = ( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT );
964 QRect rect = region2QRect( rControlRegion );
965 QPoint pos( rPos.X(), rPos.Y());
966 // Adjust coordinates to make the widget appear to be at (0,0), i.e. make
967 // widget and screen coordinates the same. QStyle functions should use screen
968 // coordinates but at least QPlastiqueStyle::subControlRect() is buggy
969 // and sometimes uses widget coordinates.
970 pos -= rect.topLeft();
971 rect.moveTo( 0, 0 );
972 QStyleOptionSlider options;
973 options.orientation = bHorizontal ? Qt::Horizontal : Qt::Vertical;
974 if( bHorizontal )
975 options.state |= QStyle::State_Horizontal;
976 options.rect = rect;
977 // some random sensible values, since we call this code only for scrollbar buttons,
978 // the slider position does not exactly matter
979 options.maximum = 10;
980 options.minimum = 0;
981 options.sliderPosition = options.sliderValue = 4;
982 options.pageStep = 2;
983 QStyle::SubControl control = kapp->style()->hitTestComplexControl( QStyle::CC_ScrollBar, &options, pos );
984 if( nPart == PART_BUTTON_UP || nPart == PART_BUTTON_LEFT )
985 rIsInside = ( control == QStyle::SC_ScrollBarSubLine );
986 else // DOWN, RIGHT
987 rIsInside = ( control == QStyle::SC_ScrollBarAddLine );
988 return TRUE;
990 return FALSE;
993 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */