branches/work/kwin_composite becomes new trunk kwin.

svn path=/trunk/KDE/kdebase/workspace/; revision=659202
This commit is contained in:
Luboš Luňák 2007-04-29 17:35:43 +00:00
parent 2b7e1f4993
commit f52b8e48cd
411 changed files with 74997 additions and 0 deletions

100
CMakeLists.txt Normal file
View file

@ -0,0 +1,100 @@
project(kwin)
add_definitions (-DQT3_SUPPORT)
add_subdirectory( lib )
add_subdirectory( killer )
add_subdirectory( kcmkwin )
add_subdirectory( pics )
add_subdirectory( clients )
add_subdirectory( effects )
add_subdirectory( data )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}/lib
${CMAKE_CURRENT_SOURCE_DIR}/lib
${CMAKE_CURRENT_SOURCE_DIR}/effects
)
configure_file(config-kwin.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwin.h )
include_directories(${CMAKE_CURRENT_BINARY_DIR})
########### next target ###############
set(kwin_KDEINIT_SRCS
workspace.cpp
client.cpp
placement.cpp
atoms.cpp
utils.cpp
layers.cpp
main.cpp
popupinfo.cpp
tabbox.cpp
options.cpp
plugins.cpp
events.cpp
killwindow.cpp
geometrytip.cpp
sm.cpp
group.cpp
bridge.cpp
manage.cpp
notifications.cpp
activation.cpp
useractions.cpp
geometry.cpp
rules.cpp
composite.cpp
toplevel.cpp
unmanaged.cpp
scene.cpp
scene_basic.cpp
scene_xrender.cpp
scene_opengl.cpp
deleted.cpp
effects.cpp
)
qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWin::Workspace )
kde4_automoc(kwin ${kwin_KDEINIT_SRCS})
kde4_add_kdeinit_executable( kwin ${kwin_KDEINIT_SRCS})
target_link_libraries(kdeinit_kwin ${KDE4_KDEUI_LIBS} kdecorations kwineffects ${X11_LIBRARIES} ${QT_QT3SUPPORT_LIBRARY} )
if(OPENGL_FOUND)
target_link_libraries(kdeinit_kwin ${OPENGL_gl_LIBRARY})
# -ldl used by OpenGL code
target_link_libraries(kdeinit_kwin -ldl)
endif(OPENGL_FOUND)
if (X11_Xrandr_FOUND)
target_link_libraries(kdeinit_kwin ${X11_Xrandr_LIB})
endif (X11_Xrandr_FOUND)
if (X11_Xcomposite_FOUND)
target_link_libraries(kdeinit_kwin ${X11_Xcomposite_LIB})
endif (X11_Xcomposite_FOUND)
if (X11_Xdamage_FOUND)
target_link_libraries(kdeinit_kwin ${X11_Xdamage_LIB})
endif (X11_Xdamage_FOUND)
if (X11_Xrender_FOUND)
target_link_libraries(kdeinit_kwin ${X11_Xrender_LIB})
endif (X11_Xrender_FOUND)
if (X11_Xfixes_FOUND)
target_link_libraries(kdeinit_kwin ${X11_Xfixes_LIB})
endif (X11_Xfixes_FOUND)
install(TARGETS kdeinit_kwin DESTINATION ${LIB_INSTALL_DIR} )
target_link_libraries( kwin kdeinit_kwin )
install(TARGETS kwin DESTINATION ${BIN_INSTALL_DIR})
########### install files ###############
install( FILES kwin.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
install( FILES kwin.notifyrc DESTINATION ${DATA_INSTALL_DIR}/kwin )
kde4_install_icons( ${ICON_INSTALL_DIR} )

247
COMPLIANCE Normal file
View file

@ -0,0 +1,247 @@
W A R N I N G:
--------------
This document is a work in progress and is in no way complete or accurate!
Its current purpose is in aiding the KWin NetWM audit for a future KWin release.
NetWM Compliance Document:
==========================
Listed below are all the NetWM (or EWM) hints decided upon on freedesktop.org
(as of version 1.3draft, Nov 27, 2002) and KWin's current level of
compliance with the spec. Some parts also involve the pager and clients which
this document will cater for as well where applicable.
If you modify the level of NetWM compliance (via modification of kwin/*,
kdecore/netwm.* or kdecore/kwin.* etc.), or notice any new hints that
were added after version 1.2, please modify this document appropriately.
Properties are ordered in the table in the order they are found in the
specification. To list any important notes regarding a property, just
add them as follows:
_NET_NUMBER_OF_DESKTOPS root window property done
+----------------------------------------------------------------+
| This property SHOULD be updated by the Window Manager to |
| indicate the number of virtual desktops. KWin DOES update this |
| property when the pager changes the number of desktops. |
+----------------------------------------------------------------+
If you have any questions regarding the specification, feel free to ask on the KWin
mailing list <kwin@kde.org>, or on the Window Manager Spec list <wm-spec-list@gnome.org>.
-- Karol <kszwed@kde.org>
(
compliance :
- = none,
/ = partial,
+ = complete,
* = KWin is compliant, but something else needs checking (e.g. Qt)
? = unknown
)
NETWM spec compliance (whole document):
version 1.2
======================
+ 1.
+ 2.3. Feature not implemented.
+ 2.4. Feature not implemented.
+ 2.5.
+ 2. (rest of the section)
+ 3.1.
This property is complete in the sence that all implemented properties
are listed here.
CHECKME : check it's complete
/ 3.2.
The spec requires that _NET_CLIENT_LIST contains the windows in their
initial mapping order, which is currently not true for NET::Desktop
windows.
Note that xprop lists only first element in WINDOW type properties.
+ 3.3.
Note that KWin does not use the virtual root windows technique,
so it doesn't set _NET_VIRTUAL_ROOTS at all.
+ 3.4.
KWin doesn't implement large desktops, so it ignores
the message, and only sets the property to the screen size.
+ 3.5.
KWin doesn't implement viewports, so it correctly sets
the property to (0,0) pairs and ignores the message.
+ 3.6.
+ 3.7.
+ 3.8.
KWin currently extends the message a bit, with data.l[0] being 1 or 2,
meaning 'from application'/'from pager', and data.l[1] contains
timestamp. This is used for focus stealing prevention purposes, and
will be proposed for next version of the spec.
+ 3.9.
+ 3.10.
+ 3.11.
KWin doesn't use the virtual roots technique for creating virtual
desktops, so it doesn't set the property.
- 3.12.
- 3.13.
+ 4.1.
+ 4.2.
+ 4.3.
Due to implementation details KWin actually allows moving or resizing
by keyboard when requested to be done by mouse, and vice versa.
+ 5.1.
+ 5.2.
+ 5.3.
+ 5.4.
+ 5.5.
/ 5.6. The handling of _NET_WM_WINDOW_TYPE itself is correct and complete.
Supported window types: DESKTOP, DOCK, TOOLBAR, MENU, UTILITY,
SPLASH, DIALOG, NORMAL.
UTILITY should get better placement.
TOOLBAR - many parts in KDE still treat this as "tool" window.
- should the decoration be shown for the toolbars?
KDE extensions:
_KDE_NET_WM_WINDOW_TYPE_TOPMENU - this is used for implementing
standalone menubars for applications. Only the menubar
that is transient for the currently active window will be shown.
See KMenuBar class in libkdeui for details.
_KDE_NET_WM_WINDOW_TYPE_OVERRIDE - this seems to mean "this window
should be borderless", but it's actually used also for other
things, like fullscreen windows. The plan is to get rid of this
flawed thing as soon as possible.
/ 5.7.
The handling of _NET_WM_STATE itself is correct and complete.
Supported states: MODAL, MAXIMIZED_VERT, MAXIMIZED_HORZ, SHADED,
SKIP_TASKBAR, SKIP_PAGER, HIDDEN, ABOVE, BELOW.
STICKY is not supported, because KWin doesn't implement viewports.
BELOW - in order to make 'allow windows to cover the panel' feature
in Kicker work KWin interprets this state a bit differently
for DOCK windows. While normal DOCK windows are in their
extra layer above normal windows, making them BELOW doesn't
move them below normal windows, but only to the same layer, so
that windows can hide Kicker, but Kicker can be also raised
above the windows. A bit hacky, but it's not really against
the spec, and I have no better idea.
KDE extensions:
_NET_WM_STATE_STAYS_ON_TOP - has the same meaning like ABOVE,
and is deprecated in favour of it; it lacks the _KDE prefix
* 5.8.
The handling of _NET_WM_ALLOWED_ACTIONS itself is correct and complete.
Supported actions: MOVE, RESIZE, MINIMIZE, SHADE, MAXIMIZE_HORZ,
MAXIMIZE_VERT, CHANGE_DESKTOP, CLOSE
STICK is not supported, because KWin does not implement viewports.
Kicker etc. need to be updated.
+ 5.9.
* 5.10.
Property is not used in KWin.
Kicker needs to be checked.
* 5.11.
KWin's handling of the property is correct.
Qt should be checked.
+ 5.12.
- 5.13.
Property is not used in KWin, KWin never provides icons for iconified windows.
Kicker or its taskbar don't set it either. However, the property is flawed,
and should be replaced by manager selection or similar mechanism.
+ 6.1.
+ 6. (rest)
+ 7.4.
The urgency hint is mapped to the _NET_WM_DEMANDS_ATTENTION flag.
* 7.5.
Qt often sets maximum size smaller than minimum size. This seems to be caused
by delayed layout calculations.
* 7.6.
Kicker should be checked.
? 7.7.
+ 7. (rest of the section)
ICCCM spec compliance (whole document):
version 2.0
======================
/ 1.2.3.
KWin uses KWIN_RUNNING atom that's missing the leading underscore.
Some parts of KDE perhaps may be missing the leading underscore.
/ 1.2.6.
Should be checked.
+ 1. (rest of the section)
+ 2.8. kmanagerselection.* in kdecore
+ 2. (rest of the section)
Not a KWin thing.
* - patch sent to TT to make QClipboard sufficiently compliant
+ 3.
Feature not supported, obsolete.
+ 4.1.1
+ 4.1.2 (intro)
+ 4.1.2.1
Used as a fallback for _NET_WM_NAME.
+ 4.1.2.2
Used as a fallback for _NET_WM_ICON_NAME.
? 4.1.2.3
? - PSize, PPosition, USize, UPosition
? - clients - Qt simply sets both
+ - PWinGravity - window geometry constraints have higher priority than gravity
/ - PBaseSize - PMinSize is not used as a fallback for size increments
+ - (the rest)
/ 4.1.2.4
+ - input - see 4.1.7
+ - initial_state
+ - icon - feature not supported
+ - window_group
+ - urgency - mapped to _NET_WM_DEMANDS_ATTENTION
/ 4.1.2.5 - it should be checked it's used correctly in Kicker etc.
/ 4.1.2.6 - should be checked
NETWM section 7.3. is supported too, even though it's a slight ICCCM violation.
+ 4.1.2.7
- 4.1.2.8
See 4.1.8.
+ 4.1.2.9 - handled by Xlib call
+ 4.1.3.1
+ 4.1.3.2
Feature not supported (4.1.2.4 - icons)
* 4.1.4 it should be checked Qt/KDE clients handle this properly
/ 4.1.5
This needs fixing.
+ 4.1.6
+ 4.1.7
- 4.1.8
KWin only installs colormap required by the active window.
- 4.1.9
Feature not supported, except for WM_ICON_NAME as a fallback for _NET_WM_ICON_NAME.
+ 4.1.10
+ 4.1.11
Window groups are only used for supporting NETWM section 7.3.
+ 4.2.5
/ 4.2.7
Qt doesn't set revert-to to Parent.
+ 4.2.8.1 frozen clients may be XKill-ed upon a user request though
+ 4.3
? 4.4
+ 4. (rest of the section)
+ 5.3. not KWin related
+ 5. (rest of the section )
? 6.1. clients thing
? 6.2. clients thing - Qt perhaps should force rule 2.
+ 6.3.
? 6. (rest of the section)
+ 7. - no idea what it is, but it doesn't seem to be KWin related
+ 8.
KDE-specific extensions (for completeness):
Property Name Type
==========================================================================
_KDE_WM_CHANGE_STATE root window message
_KDE_NET_SYSTEM_TRAY_WINDOWS root window property
_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR window property
_KDE_NET_WM_FRAME_STRUT window property
_NET_WM_CONTEXT_HELP
- Qt extension
- has no vendor prefix even though it's not part of the spec
_NET_WM_STATE_STAYS_ON_TOP
- KDE extension
- has no vendor prefix even though it's not part of the spec
- deprecated in favor of _NET_WM_STATE_KEEP_ABOVE
_KDE_NET_WM_WINDOW_TYPE_OVERRIDE
- window type, makes the window borderless
- unclear semantics, used also for fullscreen windows
- deprecated in favor of other window types
==========================================================================

102
COMPOSITE_HOWTO Normal file
View file

@ -0,0 +1,102 @@
This file describes how to set up kwin_composite. Note that since it is still
a work in progress, this file may possibly get out of date at times.
See file HACKING for details on developing KWin, including building
the kwin_composite branch.
See file COMPOSITE_TODO for a list of things that still need to be done.
See effects/howto.* for a HOWTO on writting effects.
See documentation in source (mainly in scene.cpp) for description
of the design of the compositing framework.
Using kwin_composite branch:
============================
See the KDE trunk HOWTO at http://developer.kde.org/build/trunk.html .
The simplest way to build the kwin_composite branch is to switch the trunk version
to the branch:
$ cd kdebase/workspace/kwin
$ svn info
(prints the repository URL, for example https://svn.kde.org/home/kde/trunk/KDE/kdebase/workspace/kwin)
$ svn switch https://svn.kde.org/home/kde/branches/work/kwin_composite
(i.e. replace trunk/KDE/kdebase/workspace/kwin with branches/work/kwin_composite)
$ make
(i.e. build and use it as usually)
After starting, KWin's debug output also says which compositing backend it uses, e.g.
"OpenGL compositing". If it does not, most probably your X is not configured properly.
nVidia:
-----------
Both 9xxx and 8xxx drivers work, only 9xxx drivers provide TFP (texture_from_pixmap)
functionality.
You need in xorg.conf
Option "AddARGBGLXVisuals" "True"
in 'Section "Screen"' and also the XComposite extension enabled:
Section "Extensions"
Option "Composite" "Enable"
EndSection
ATI:
--------
The radeon driver should work for R200 chips, it's worse with R300 chips.
TODO - fglrx - no idea
You need in xorg.conf the XComposite extension enabled:
Section "Extensions"
Option "Composite" "Enable"
EndSection
Also using
Option "XaaNoOffscreenPixmaps" "true"
in 'Section "Screen"' may improve performance for non-TFP (texture_from_pixmap) modes.
For the TFP mode AIGLX needs to work. With AIGLX direct rendering should be be disabled
(see GLDirect below, with X.org older than 7.2 "export LIBGL_ALWAYS_INDIRECT=1" before
running kwin may be necessary).
Intel:
-------
TODO - no idea. Possibly similar to ATI.
Configuration options:
----------------------
All general configuration option are in group [Translucency] in kwinrc config file:
UseTranslucency=<true|false> - enables/disables compositing support
GLMode=<TFP|SHM|Fallback> - selects texture creating mode
RefreshRate=<number> - manually specified refresh rate, should be usually automatically detected
GLAlwaysRebind=<true|false> - may increase speed with some graphics cards
GLDirect=<true|false> - enables/disables direct rendering
GLVSync=<true|false> - enables/disables synchronizing with monitor refresh
ShowFPSEffect:
Options are in group [EffectShowFps] in kwinrc config file:
Alpha=<number 0.0-1.0> - transparency
X=<number> - X position, negative is from the right edge, -10000 is exactly right edge
Y=<number> = Y position, the same like X
Effects:
--------
Which modules are enabled is currently set by config value Load in group [Effects] in kwinrc config file.
Effects are named like the class, without the Effect suffix (e.g. Load=ShowFps,Fade). There is
no depedency checking implemented yet.

262
COMPOSITE_TODO Normal file
View file

@ -0,0 +1,262 @@
This file lists TODO items for the compositing code.
See file COMPOSITE_HOWTO for setting up kwin_composite.
See file HACKING for details on developing KWin, including building
the kwin_composite branch.
See effects/howto.* for a HOWTO on writting effects.
See documentation in source (mainly in scene.cpp) for description
of the design of the compositing framework.
TODO
=================================
* = not done, will be either done by me, or should be at least discussed first with me
+ = not done, I don't plan on doing it that soon
- in other words, these should be the best ones for you if you want to help
! = like +, but they should be relatively simple
- in other words, these should be the best if you want to get started with the code
/ = work in progress
? = should it be done?
% = should be probably done later, during cleanups and preparations for being stable
General TODO
=================================
? alpha clear hack
+ - find out if it affects performance
+ - if yes, try to find a better way of solving the problem
! - since kompmgr has an option to make only the decoration transparent,
it should be possible to do the same here - if the window has alpha and a decoration
or if there should be only the decoration transparent, paint first the contents
and then the decoration - this should make it possible to paint the decoration
without the random alpha that is right now handled by the alpha hack
? wait for decoration repaints
- it is sometimes visible that the window contents are painted first and the decoration
only afterwards with a small delay
? - this has been already greatly improved by r632378, so it's maybe not worth it anymore
- maybe posted paint events need to be processed immediatelly, or maybe the compositing
code should not update the window until the decoration is finished painting
? Expose events for overlay window - is it necessary to track it, like with root window?
% paint throttling
- there's 5ms grace period per repaint to avoid overloading the system with just compositing
and not letting the system do anything else - check and evaluate
% support for new window types from the wm spec for compositing
- this will have to be done in Qt, kdecore and kwin
* handle properly stacking order of deleted windows for showing in effects
* handle properly deleted windows that reappear (windowReadded() function?)
/ consider using an extra class for representing deleted windows
- cleaning up Client/Unmanaged instances may still leave e.g. timers around if they're overlooked
- an extra class could copy some interesting data and "replace" the old instance
% during screensaving, do no let non-screensaver windows show above screensaver
- kdesktop_lock watches for such things and raises again, but there's a small gap
% nvidia drivers by default use fake refresh rates as a workaround for some X limitations
- see the DynamicTwinView section in nvidia README
- this makes KWin repaint at a different rate than it should
* handling of window pixmap for unmapped windows
- currently it's kept around after a window is unmapped
* - but it's still discarded on e.g. resize - how to solve this?
* - perhaps there should be an option not to unmap windows in order to always have live thumbnails
* - another option could be to unmap but quickly map when a live thumbnail is needed
* cursorPos() does not work reliably now (not from e.g. timers, it needs events), so it's disabled
* window grouping is not implemented for unmanaged windows (used e.g. by DimInactive)
% clean up and sort out shortcuts so that they don't conflict and make sense
- also make configurable etc.
OpenGL TODO
=================================
/ Check/make it work with other gfx cards
? Xgl support
- Compiz itself doesn't work when compiled with the libGL from nvidia,
it ships its own and links against it
? - might be worth trying to use that libGL as well
- it may be just because of the special libGL, but when testing with Xgl
it even seemed non-conformant - none of the provided configs had
GLX_RENDER_TYPE with GLX_RGBA_BIT even though required by GLX
and other funny things. Indeed, it may be just me being still pretty
clueless about these things.
? - is there a good reason to support Xgl? With the 9625 nvidia drivers
it seems to work fine without them and there's AIGLX
+ AIGLX support
- kind of works, needs more work
+ - it needs indirect rendering, should be autodetected and disabled somehow
% - may require LIBGL_ALWAYS_INDIRECT set with older X.org
(http://lists.kde.org/?l=kwin&m=116439615124838&w=2)
(http://lists.freedesktop.org/archives/xorg/2006-December/020323.html)
/ GL_ARB_texture_rectangle vs GL_ARB_texture_non_power_of_two
% - works; bugs in tfp_mode with power_of_two textures
- ati (others?): power_of_two windows are drawn white unless non-tfp_mode
is forced in findTextureTarget()
? in SceneOpenGL::bindTexture() with tfp_mode, with some gfx cards it seems
to be faster to not short-circuit the texture binding when there's been
no damage
+ strict binding
- there is code to support strict binding as required by AIGLX, but it's disabled, because
copy_buffer in bindTexture() ensures strict binding as a side-effect
- since copy_buffer hack should be removed in the future, strict binding will need to be enabled then
- http://lists.kde.org/?l=kwin&m=116363084129170&w=2
% bindTexture() optimize copied areas
- right now bindTexture() updates every damaged area and resets the window damage
- it might make things faster to update only areas that need to be repainted
and keep the rest damaged until needed
% clipping optimization
- like XRender code has paintTransformedScreen(), avoid painting parts that are
obscured (makes a difference with many windows open)
- http://lists.kde.org/?l=kwin&m=116585618111882&w=2
+ shm mode needs support for more data formats than GL_BGRA in order to support e.g. 16bpp mode
- http://www.xfree86.org/current/glTexImage2D.3.html
% with current nvidia glXCreatePixmap in tfp mode fails with pixmaps 32x32 and smaller
+ vertices list (and possibly more things) should not be part of SceneOpenGL::Window
- otherwise drawWindow() used for thumbnails would use them too
- they should be probably part of WindowPaintData
XRender TODO
==============================
+ SceneXrender::Window::performPaint() doesn't use saturation
+ SceneXrender::Window::performPaint() doesn't use brightness
+ SceneXrender::paintTransformedScreen() doesn't handle properly extending of painted area
in window's pre-paint - see the transformedShape() comment
Effects framework TODO
==============================
* more notification functions for effects are needed
- currently there are only very few notification functions (windowAdded, windowActivated,...)
! - window state changes
? more
/ shadows
+ - right now is only a rectangle, probably needs some shape support
+ - right now is only a flat black color, probably should be improved
/ support for grabbing input
- during some more complicated effects, input (at least mouse) should be disabled,
because currently there is no way to do input redirection
? pre-paint pass should be done completely before the paint pass
- currently prePaintWindow() is done only after paintScreen() has already started,
which means that if an effect sets PAINT_WINDOW_TRANSFORMED it needs to set it
also in prePaintScreen()
* PAINT_DISABLED turning off from effects needs some improvement
- a window may have painting disabled for various reasons and their numbers may increase
over time
- so e.g. an effect showing minimized windows cannot simply turn off DISABLED
for minimized windows, because it may be disabled also for other reasons
- there should be some utility function that will be called by the effect
with arguments saying which disabled windows it wants enabled
+ EffectWindow should be completely opaque when kept as the only API for effects
- no inlines, etc.
+ API for tabbox for effects should be cleaned up
* check Scene::updateTimeDiff() - should the time be 0 or 1?
* DesktopGridEffect has somewhat broken stacking order while moving windows
- the window is in proper layer when on its desktop but on top of everything when moved
to another desktop, due to its desktop being painted later
- maybe there should be PAINT_WINDOW_TOP (_LAST or whatever) that'd make it painted always
on top of everything
% post calls are probably not necessary by now (http://lists.kde.org/?t=117770818100003&r=1&w=2)
Effects TODO
===============================
+ adapt the kcontrol module used by Kompmgr
- in kcmkwin/kwinoptions
! - uses ~/.xcompmgr, convert to use normal KConfig
? - I don't think these effects should be plugins or anything like that,
probably simply write to kwinrc and use the Option class in KWin
/ implements all effects Kompmgr could do
+ - all effects from the Opacity tab should be already doable
! - applying translucency only to the decoration
- use clientSize() and clientPos() from Client
- see also the alpha clear hack todo entry
! - not usign ARGB visuals
- just clear the alpha channel in the alpha clear hack
- or do it while painting (see also the alpha clear hack todo entry)
! - the rest - should be simple
/ - shadows
+ - tab Effects
+ - fade between changes
- will need notification about opacity changes
- not sure if this is doable for other opacity changes then the ones
initiated by the user or by the application
+ minimize/shade effects
- to replace the ones from KWin core
/ - minimizing
- check support for it and the avoid_animation flag
+ - shading
- shading will probably need special support
/ zoom effect
- enlarge a portion of the screen
+ logout effect
* - should be triggered by ksmserver somehow
+ effects to replace widget effects (the ones in the Effects tab in "kcmshell style")
+ - needs support for new window types from the current draft of the EWMH WM spec
+ - needs patching Qt, netwm* classes in kdecore
/ showfps effect
- for debugging, just shows transparent fps in some corner
- just painting the number in paintScreen() should do, with glPushMatrix() and glLoadIdentity()
to avoid all transformations
+ - needs bindPixmapToTexture() or something like that, for displaying the text
- should also detect kwin being idle - it probably should detect in pre-paint that the only
damage is its own area and avoid damaging for the next round in post-paint
+ debugpaint effect
- should show what is damaged during each repaint step
- probably just e.g. paint a red almost transparent area over damaged areas
- needs special care to avoid causing infinite loops by its own damage (i.e. it damages
part of screen to clear its own painting, that triggers itself again next repaint)
? other effects
+ virtual desktop change effects
+ - ... yes, you guessed it, the cube
+ - something that presents all virtual desktops as being in grid (as in pager)
and zooms out of the old one and into the new one
- or whatever
* DimInactive flickers when switching between windows (temporarily no window becomes active)
+ TrackMouse needs a better way of activating
- LMB+RMB is problematic, some systems handle that as MMB, and LMB+RMB press is still
two consequent events

183
HACKING Normal file
View file

@ -0,0 +1,183 @@
Mailing list and bugzilla:
==========================
The KWin mailing list is kwin@kde.org . It's rather low traffic.
The bugs.kde.org product for KWin is 'kwin'. Currently the components are 'general' (KWin core),
'decorations' (decoration plugins), 'compatibility' (problems with non-KDE WMs/apps),
'eyecandy' (transparency and similar effects), 'xinerama' (problems with Xinerama) and
'multihead' (non-Xinerama multihead, without maintainer).
There are also two kcontrol components 'kcmkwindecoration' and 'kcmkwinoptions' related
to KWin's KControl modules.
KWin parts:
===========
There are four parts of KWin:
- The KWin core, located in kdebase/kwin/*, which implements the actual functionality.
- The decoration plugins, located in kdebase/kwin/clients and kdeartwork/kwin-styles, which
are responsible for the visual representation of the windows.
- The libkdecoration library, located in kdebase/kwin/lib/*, which is used for communication
between the core and the decoration, and also implements some shared functionality
for the decorations.
- KControl modules, located in kdebase/kwin/kcmkwin.
KWin decorations:
=================
If you want to develop a decoration plugin for KWin, a HOWTO is available at
http://www.usermode.org/docs/kwintheme.html . It is currently not possible to create
a new decoration without knowledge of C++, but it should be possible to write a themeable
decoration (I'm not aware of any such decoration though).
Restarting KWin:
================
Since KWin takes care of focus handling, first killing KWin and then launching new instance
can cause focus trouble. Therefore it's possible to run 'kwin --replace', which will start
new KWin instance and tell the old one to quit.
Handling the case when KWin crashes:
====================================
Again, without KWin running there may be focus problems. The simplest way to solve them
is to add the 'Run Command' applet to Kicker - it can receive focus even without KWin running.
If you can't add the applet or can reach it for some reason, switch to text console, and run
'DISPLAY=:0 kwin --replace' (and then you can run 'kwin --replace' again from X).
If KWin is temporarily unusable because of some change and e.g. crashes during startup, it
is possible to run another window manager, for example Metacity, OpenBox or FVWM (the command
is similar to restarting KWin, i.e. 'metacity --replace', 'openbox --replace' or 'fvwm -replace').
Debugging KWin:
===============
Focus problems once more. It is not possible to debug KWin in gdb in the X session that KWin is managing,
because that'd block focus and window operations. It is necessary to switch to a text console
and attach to the running KWin instance from there, or launch it as 'DISPLAY=:0 gdb kwin'.
Since KWin is such an important component of KDE, it is usually better to start another X for development.
Note that XNest is quite buggy and is therefore not recommended to use.
Starting separate X for testing KWin: I myself use a separate user, login to a text console and run
"( X vt10 :1 -terminate &); sleep 5; DISPLAY=:1 xterm". This launches another X with DISPLAY=:1
on virtual console 10 (Ctrl+Alt+F10) with xterm. Then it's normally possible to run just KWin
or whole KDE with startkde (in which case it's a good idea to disable xterm from session management
in KControl->KDE components->Session manager).
Window manager spec:
====================
The EWMH window manager specification, also known as NETWM, is located at the freedesktop.org site,
http://www.freedesktop.org/wiki/Standards_2fwm_2dspec . It defines how the window manager
communicates information with the applications and other desktop utilities such as the taskbar
or pager.
KWin structure:
===============
KWin has relatively few classes. The two main classes are Client, which represents windows
on the screen, and Workspace, which represents the whole screen and manages windows. Since
KWin also needs to track unmanaged windows for compositing, there is a base class Toplevel
for all windows, from which Client inherits, and from which also class Unmanaged inherits.
These classes are rather large, because they fulfil complicated tasks. In other to reduce size
of their source files these some functionality is in separate .cpp file grouped by the purpose:
- workspace.* - core of class Workspace
- client.* - core of class Client
- toplevel.* - core of the base class Toplevel
- unmanaged.* - core of the class Unmanaged
- activation.cpp - focus handling and window activation
- composite.cpp - code related to redirecting windows to pixmaps and tracking their damage
- events.cpp - event handling is in events.cpp
- geometry.cpp - geometry-related code
- layers.cpp - stacking-related code
- manage.cpp - code dealing with new windows
- placement.cpp - window placements algorithms
- rules.cpp - code for window-specific settings
- sm.cpp - session management code
- useractions.cpp - handling of the Alt+F3 menu, shortcuts and other user actions
The rest of the files contain additional helper classes:
- atoms.* - so-called atoms (symbolic names for constants in X)
- bridge.* - communication with the decoration plugin
- effects.* - support for compositing effects
- geometrytip.* - window displaying window geometry while moving/resizing
- group.* - grouping related windows together (warning! This is currently really messy and scary code
that should be rewritten).
- killwindow.* - handling of the Ctrl+Esc feature
- kwinbindings.cpp - KWin's keyboard shortcuts (used by kdebase/kcontrol/keys)
- notifications.* - for KNotify
- options.* - all configuration options for KWin are stored in this class
- plugins.* - loading of the right decoration plugin
- popupinfo.* - showing temporary information such as virtual desktop name when switching desktops
- scene.* - base class for compositing backends, with shared functionality
- scene_basic.* - a very simple testing compositing code
- scene_opengl.* - compositing backed using OpenGL
- scene_xrender.* - compositing backend using XRender
- tabbox.* - the Alt+Tab dialog
- utils.* - various small utility functions/classes
KWin also uses code from kdelibs, specifically files netwm.cpp, netwm.h, netwm_def.h and netwm_p.h
from kdelibs/kdecore. These files implement support for the EWMH window manager specification,
originally called NETWM (hence the filenames).
Developing KWin:
================
So, you feel brave, huh? But KWin is not THAT difficult. Some parts, especially the X-related ones,
can be very complicated, but for many parts even knowledge of X and Xlib is not necessary. Most X
code is wrapped in helper functions, and I can handle problems there ;) . However, although many
features don't require touching X/Xlib directly, still X/Xlib may impose their semantics on the way
things are done. When in doubt, simply ask.
All patches for KWin core should be sent to kwin@kde.org for review first. Even seemingly harmless
changes may have extensive consequences.
Various notes:
- kDebug has overloaded operator << for the Client class, so you can e.g. use 'kDebug() << this << endl;'
in class Client and it will print information about the window.
- KWin itself cannot create any normal windows, because it would have trouble managing its own windows.
For such cases (which should be rare) a small external helper application is needed (kdialog should often
do, and for special cases such a utility needs to be written like kwin/killer).
Coding style:
=============
There are these rules for patches for KWin:
- the code should be relatively nice and clean. Seriously. Rationale: Any messy code can be hard to comprehend,
but if the code is in a window manager it will be twice as difficult.
- unless the functionality of the code is obvious, there should be either at least a short comment explaining
what it does, or it should be obvious from the commit log. If there's a hack needed, if there's a potentional
problem, if something is just a temporary fix, say so. Comments like "this clever trick is necessary"
don't count. See above for rationale. I needed more than two years to understand all of KWin,
and there were parts I never got and had to rewrite in order to fix a problem with them.
- indentation is 4 spaces, not tabs. Rationale: The code looks like a mess if this is not consistent.
- { and } enclosing a block are aligned with the block, neither with the above level nor there is any
trailing { (i.e. { and } are indented in the same column like the code they surround). See above for rationale.
If this feel weird or whatever, put them wherever you want first and when the changes are done, check
"svn diff" and fix it. If I can handle about half a dozen different formatting styles when working
on various parts of KDE, this shouldn't be that much work for you (and yes, I've even done
the "fix-before-submit" thing).
- there is not space before (, i.e. it's "foo(", not "foo (". Rationale: This makes it simpler to grep for functions.
That's all. Bonus points if you try to follow the existing coding style in general, but I don't think
I really care about the rest, as long as these rules are followed. If I find out I care about more,
I'll add them here.
kwin@kde.org

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
Since KDE3.2, KWin is licensed under the terms of the General Public License.
See file "COPYING" in the toplevel directory for the exact licensing terms.
KWin versions in KDE3.1.x and older used the following license:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

2
Messages.sh Normal file
View file

@ -0,0 +1,2 @@
#! /usr/bin/env bash
$XGETTEXT *.h *.cpp killer/*.cpp lib/*.cpp -o $podir/kwin.pot

44
NEWCOLORSCHEME.README Normal file
View file

@ -0,0 +1,44 @@
KWin can now handle some new color scheme entries in addition to the ones
handled by KWM. Note that these are suggestions and all the colors may not
be used by all KWin styles. These all currently go into the [WM] group.
frame, inactiveFrame : Window frame (was fixed to general KDE bg in KWM).
handle, inactiveHandle : Window handles (sometimes called "grips").
activeBackground, inactiveBackground : Tilebars (bad name, but it's what KWM
uses). This is for styles that use a solid filled rectangle for the titlebar
such as the standard style and KStep.
activeGroove, inactiveGroove: This is for titlebars that instead of a solid
rectangle use some sort of groove or small bevels layered on the frame.
An example of this is System.
activeBlend, inactiveBlend : Titlebar blend for styles that use a rectangle
titlebar fill.
activeForeground, inactiveForeground : Tilebar text for styles that use a
rectangle titlebar fill.
activeGrooveText, inactiveGrooveText: Titlebar text for styles that use
grooved titlebar styles instead of the solid fill. This should contrast with
the frame color.
activeTitleBtnBg, inactiveTitleButtonBg : Button background color for up and
down states.
activeTitleBtnBlend, inactiveTitleBtnBlend : Button blend.
activeTitleBtnFg, activeTitleBtnFg : Some style's buttons don't use the
above button background colors but instead draw the button foreground
transparently on the frame. The best example of this is the standard KDE
style. Use this to specify a color for such styles, which should contrast with
the frame - not the button bg.
activeTitleBtnFullFg, inactiveTitleBtnFullFg: This is for styles that have
full support for button background settings. Examples are KStep and System.
This should contrast with the button background.
Daniel M. Duley
mosfet@kde.org
mosfet@linuxmandrake.com

189
README Normal file
View file

@ -0,0 +1,189 @@
This README is meant as an explanation of various window manager related
mechanisms that application developers need to be aware of. As some of these
concepts may be difficult to understand for people not having the required
background knowledge (since sometimes it's difficult even for people who
do have the knowledge), the mechanisms are first briefly explained, and
then an example of fixing the various problems is given.
For comments, questions, suggestions and whatever use the kwin@kde.org
mailing list.
Table of contents:
==================
- Window relations
- how to make the window manager know which windows belong together
- Focus stealing prevention
- how to solve cases where focus stealing prevention doesn't work
properly automatically
Window relations:
=================
(For now, this explanation of window relations is mainly meant for
focus stealing prevention. To be extended later.)
All windows created by an application should be organized in a tree
with the root being the application's main window. Note that this is about
toplevel windows, not widgets inside the windows. For example, if you
have KWrite running, with a torn-off toolbar (i.e. a standalone toolbar),
a file save dialog open, and the file save dialog showing a dialog
for creating a directory, the window hiearchy should look like this:
KWrite mainwindow
/ \
/ \
file save dialog torn-off toolbar
\
\
create directory dialog
Each subwindow (i.e. all except for the KWrite mainwindow) points to its
main window (which in turn may have another main window, as in the case
of the file save dialog). When the window manager knows these relations,
it can better arrange the windows (keeping subwindows above their
main windows, preventing activation of a main window of a modal dialog,
and similar). Failing to provide this information to the window manager
may have various results, for example having dialogs positioned below
the main window,
The window property used by subwindows to point to their mainwindows is
called WM_TRANSIENT_FOR. It can be seen by running
'xprop | grep WM_TRANSIENT_FOR' and clicking on a window. If the property
is not present, the window does not (claim to) have any mainwindow.
If the property is present, it's value is the window id of its main window;
window id of any window can be found out by running 'xwininfo'. A window
having WM_TRANSIENT_FOR poiting to another window is said to be transient
for that window.
In some cases, the WM_TRANSIENT_FOR property may not point to any other
existing window, having value of 0, or pointing to the screen number
('xwininfo -root'). These special values mean that the window is transient
for all other windows in its window group. This should be used only
in rare cases, everytime a specific main window is known, WM_TRANSIENT_FOR
should be pointing to it instead of using one of these special values.
(The explanation why is beyond the scope of this document - just accept it
as a fact.)
With Qt, the WM_TRANSIENT_FOR property is set by Qt automatically, based
on the toplevel widget's parent. If the toplevel widget is of a normal
type (i.e. not a dialog, toolbar, etc.), Qt doesn't set WM_TRANSIENT_FOR
on it. For special widgets, such as dialogs, WM_TRANSIENT_FOR is set
to point to the widget's parent, if it has a specific parent, otherwise
WM_TRANSIENT_FOR points to the root window.
As already said above, WM_TRANSIENT_FOR poiting to the root window should
be usually avoided, so everytime the widget's main widget is known, the widget
should get it passed as a parent in its constructor.
(TODO KDialog etc. classes should not have a default argument for the parent
argument, and comments like 'just pass 0 as the parent' should go.)
Focus stealing prevention:
==========================
Since KDE3.2 KWin has a feature called focus stealing prevention. As the name
suggests, it prevents unexpected changes of focus. With older versions of KWin,
if any application opened a new dialog, it became active, and
if the application's main window was on another virtual desktop, also
the virtual desktop was changed. This was annoying, and also sometimes led
to dialogs mistakenly being closed because they received keyboard input that
was meant for the previously active window.
The basic principle of focus stealing prevention is that the window with most
recent user activity wins. Any window of an application will become active
when being shown only if this application was the most recently used one.
KWin itself, and some of the related kdecore classes should take care
of the common cases, so usually there's no need for any special handling
in applications. Qt/KDE applications, that is. Applications using other
toolkits should in most cases work fine too. If they don't support
the window property _NET_WM_USER_TIME, the window manager may fail to detect
the user timestamp properly, resulting either in other windows becoming active
while the user works with this application, or this application may sometimes
steal focus (this second case should be very rare though).
There are also cases where KDE applications needs special handling. The two
most common cases are when windows relations are not setup properly to make
KWin realize that they belong to the same application, and when the user
activity is not represented by manipulating with the application windows
themselves.
Also note that focus stealing prevention implemented in the window manager
can only help with focus stealing between different applications.
If an application itself suddenly pops up a dialog, KWin cannot do anything about
it, and its the application's job to handle this case.
Window relations:
-----------------
The common case here is when a dialog is shown for an application, but this
dialog is not provided by the application itself, but by some other process.
For example, dialogs with warnings about accepted cookies are provided
by KCookieJar, instead of being shown by Konqueror. In the normal case,
from KWin's point of view the cookie dialog would be an attempt of another
application to show a dialog, and KWin wouldn't allow activation of this
window.
The solution is to tell the window manager about the relation between
the Konqueror main window and the cookie dialog, by making the dialog
point to the mainwindow. Note that this is not special to focus stealing
prevention, subwindows such as dialogs, toolbars and similar should always
point to their mainwindow. See the section on window relations for full
description.
The WM_TRANSIENT_FOR property that's set on dialogs to point to their
mainwindow should in the cookie dialog case point to the Konqueror window
for which it has been shown. This is solved in kcookiejar by including
the window id in the DCOP call. When the cookie dialog is shown, its
WM_TRANSIENT_FOR property is manually set using the XSetTransientForHint()
call (see kdelibs/kioslave/http/kcookiejar/kcookiewin.cpp). The arguments
to XSetTransientForHint() call are the X display (i.e. QX11Info::display()),
the window id on which the WM_TRANSIENT_FOR property is to be set
(i.e. use QWidget::winId()), and the window id of the mainwindow.
Simple short HOWTO:
To put it simply: Let's say you have a daemon application that has
DCOP call "showDialog( QString text )", and when this is called, it shows
a dialog with the given text. This won't work properly with focus stealing
prevention. The DCOP call should be changed to
"showDialog( QString text, long id )". The caller should pass something like
myMainWindow->winId() as the second argument. In the daemon, before
the dialog is shown, a call to XSetTransientHint() should be added:
XSetTransientForHint( QX11Info::display(), dialog->winId(), id_of_mainwindow );
That's it.
Non-standard user activity:
---------------------------
The most common case in KDE will be DCOP calls. For example, KDesktop's DCOP
call "KDesktopIface popupExecuteCommand". Executing this DCOP call e.g.
from Konsole as 'dcop kdesktop KDesktopIface popupExecuteCommand" will lead
to showing the minicli, but the last user activity timestamp gained from events
sent by X server will be older than user activity timestamp of Konsole, and
would normally result in minicli not being active. Therefore, before showing
the minicli, kdesktop needs to call KApplication::updateUserTimestamp().
However, this shouldn't be done with all DCOP calls. If a DCOP call is not
a result of direct user action, calling KApplication::updateUserTimestamp()
would lead to focus stealing. For example, let's assume for a moment
that KMail would use this DCOP call in case it detects the modem is not
connected, allowing to you to start KPPP or whatever tool you use. If KMail
would be configured to check mail every 10 minutes, this would lead to minicli
possibly suddenly showing up at every check. Basically, doing the above change
to kdesktop's minicli means that the popupExecuteCommand() DCOP call is only
for user scripting. (TODO write about focus transferring?)
Simply said, KApplication::updateUserTimestamp() should be called only
as a result of user action. Unfortunately, I'm not aware of any universal
way how to handle this, so every case will have to be considered separately.

915
activation.cpp Normal file
View file

@ -0,0 +1,915 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
/*
This file contains things relevant to window activation and focus
stealing prevention.
*/
#include "client.h"
#include "workspace.h"
#include <fixx11h.h>
#include <kxerrorhandler.h>
#include <kstartupinfo.h>
#include <kstringhandler.h>
#include <klocale.h>
#include "notifications.h"
#include "atoms.h"
#include "group.h"
#include "rules.h"
#include "effects.h"
#include <QX11Info>
namespace KWin
{
/*
Prevention of focus stealing:
KWin tries to prevent unwanted changes of focus, that would result
from mapping a new window. Also, some nasty applications may try
to force focus change even in cases when ICCCM 4.2.7 doesn't allow it
(e.g. they may try to activate their main window because the user
definitely "needs" to see something happened - misusing
of QWidget::setActiveWindow() may be such case).
There are 4 ways how a window may become active:
- the user changes the active window (e.g. focus follows mouse, clicking
on some window's titlebar) - the change of focus will
be done by KWin, so there's nothing to solve in this case
- the change of active window will be requested using the _NET_ACTIVE_WINDOW
message (handled in RootInfo::changeActiveWindow()) - such requests
will be obeyed, because this request is meant mainly for e.g. taskbar
asking the WM to change the active window as a result of some user action.
Normal applications should use this request only rarely in special cases.
See also below the discussion of _NET_ACTIVE_WINDOW_TRANSFER.
- the change of active window will be done by performing XSetInputFocus()
on a window that's not currently active. ICCCM 4.2.7 describes when
the application may perform change of input focus. In order to handle
misbehaving applications, KWin will try to detect focus changes to
windows that don't belong to currently active application, and restore
focus back to the currently active window, instead of activating the window
that got focus (unfortunately there's no way to FocusChangeRedirect similar
to e.g. SubstructureRedirect, so there will be short time when the focus
will be changed). The check itself that's done is
Workspace::allowClientActivation() (see below).
- a new window will be mapped - this is the most complicated case. If
the new window belongs to the currently active application, it may be safely
mapped on top and activated. The same if there's no active window,
or the active window is the desktop. These checks are done by
Workspace::allowClientActivation().
Following checks need to compare times. One time is the timestamp
of last user action in the currently active window, the other time is
the timestamp of the action that originally caused mapping of the new window
(e.g. when the application was started). If the first time is newer than
the second one, the window will not be activated, as that indicates
futher user actions took place after the action leading to this new
mapped window. This check is done by Workspace::allowClientActivation().
There are several ways how to get the timestamp of action that caused
the new mapped window (done in Client::readUserTimeMapTimestamp()) :
- the window may have the _NET_WM_USER_TIME property. This way
the application may either explicitly request that the window is not
activated (by using 0 timestamp), or the property contains the time
of last user action in the application.
- KWin itself tries to detect time of last user action in every window,
by watching KeyPress and ButtonPress events on windows. This way some
events may be missed (if they don't propagate to the toplevel window),
but it's good as a fallback for applications that don't provide
_NET_WM_USER_TIME, and missing some events may at most lead
to unwanted focus stealing.
- the timestamp may come from application startup notification.
Application startup notification, if it exists for the new mapped window,
should include time of the user action that caused it.
- if there's no timestamp available, it's checked whether the new window
belongs to some already running application - if yes, the timestamp
will be 0 (i.e. refuse activation)
- if the window is from session restored window, the timestamp will
be 0 too, unless this application was the active one at the time
when the session was saved, in which case the window will be
activated if there wasn't any user interaction since the time
KWin was started.
- as the last resort, the _KDE_NET_USER_CREATION_TIME timestamp
is used. For every toplevel window that is created (see CreateNotify
handling), this property is set to the at that time current time.
Since at this time it's known that the new window doesn't belong
to any existing application (better said, the application doesn't
have any other window mapped), it is either the very first window
of the application, or its the only window of the application
that was hidden before. The latter case is handled by removing
the property from windows before withdrawing them, making
the timestamp empty for next mapping of the window. In the sooner
case, the timestamp will be used. This helps in case when
an application is launched without application startup notification,
it creates its mainwindow, and starts its initialization (that
may possibly take long time). The timestamp used will be older
than any user action done after launching this application.
- if no timestamp is found at all, the window is activated.
The check whether two windows belong to the same application (same
process) is done in Client::belongToSameApplication(). Not 100% reliable,
but hopefully 99,99% reliable.
As a somewhat special case, window activation is always enabled when
session saving is in progress. When session saving, the session
manager allows only one application to interact with the user.
Not allowing window activation in such case would result in e.g. dialogs
not becoming active, so focus stealing prevention would cause here
more harm than good.
Windows that attempted to become active but KWin prevented this will
be marked as demanding user attention. They'll get
the _NET_WM_STATE_DEMANDS_ATTENTION state, and the taskbar should mark
them specially (blink, etc.). The state will be reset when the window
eventually really becomes active.
There are one more ways how a window can become obstrusive, window stealing
focus: By showing above the active window, by either raising itself,
or by moving itself on the active desktop.
- KWin will refuse raising non-active window above the active one,
unless they belong to the same application. Applications shouldn't
raise their windows anyway (unless the app wants to raise one
of its windows above another of its windows).
- KWin activates windows moved to the current desktop (as that seems
logical from the user's point of view, after sending the window
there directly from KWin, or e.g. using pager). This means
applications shouldn't send their windows to another desktop
(SELI TODO - but what if they do?)
Special cases I can think of:
- konqueror reusing, i.e. kfmclient tells running Konqueror instance
to open new window
- without focus stealing prevention - no problem
- with ASN (application startup notification) - ASN is forwarded,
and because it's newer than the instance's user timestamp,
it takes precedence
- without ASN - user timestamp needs to be reset, otherwise it would
be used, and it's old; moreover this new window mustn't be detected
as window belonging to already running application, or it wouldn't
be activated - see Client::sameAppWindowRoleMatch() for the (rather ugly)
hack
- konqueror preloading, i.e. window is created in advance, and kfmclient
tells this Konqueror instance to show it later
- without focus stealing prevention - no problem
- with ASN - ASN is forwarded, and because it's newer than the instance's
user timestamp, it takes precedence
- without ASN - user timestamp needs to be reset, otherwise it would
be used, and it's old; also, creation timestamp is changed to
the time the instance starts (re-)initializing the window,
this ensures creation timestamp will still work somewhat even in this case
- KUniqueApplication - when the window is already visible, and the new instance
wants it to activate
- without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
- with ASN - ASN is forwarded, and set on the already visible window, KWin
treats the window as new with that ASN
- without ASN - _NET_ACTIVE_WINDOW as application request is used,
and there's no really usable timestamp, only timestamp
from the time the (new) application instance was started,
so KWin will activate the window *sigh*
- the bad thing here is that there's absolutely no chance to recognize
the case of starting this KUniqueApp from Konsole (and thus wanting
the already visible window to become active) from the case
when something started this KUniqueApp without ASN (in which case
the already visible window shouldn't become active)
- the only solution is using ASN for starting applications, at least silent
(i.e. without feedback)
- when one application wants to activate another application's window (e.g. KMail
activating already running KAddressBook window ?)
- without focus stealing prevention - _NET_ACTIVE_WINDOW - no problem
- with ASN - can't be here, it's the KUniqueApp case then
- without ASN - _NET_ACTIVE_WINDOW as application request should be used,
KWin will activate the new window depending on the timestamp and
whether it belongs to the currently active application
_NET_ACTIVE_WINDOW usage:
data.l[0]= 1 ->app request
= 2 ->pager request
= 0 - backwards compatibility
data.l[1]= timestamp
*/
//****************************************
// Workspace
//****************************************
/*!
Informs the workspace about the active client, i.e. the client that
has the focus (or None if no client has the focus). This functions
is called by the client itself that gets focus. It has no other
effect than fixing the focus chain and the return value of
activeClient(). And of course, to propagate the active client to the
world.
*/
void Workspace::setActiveClient( Client* c, allowed_t )
{
if ( active_client == c )
return;
if( active_popup && active_popup_client != c && set_active_client_recursion == 0 )
closeActivePopup();
StackingUpdatesBlocker blocker( this );
++set_active_client_recursion;
if( active_client != NULL )
{ // note that this may call setActiveClient( NULL ), therefore the recursion counter
active_client->setActive( false );
}
active_client = c;
Q_ASSERT( c == NULL || c->isActive());
if( active_client != NULL )
last_active_client = active_client;
if ( active_client )
{
updateFocusChains( active_client, FocusChainMakeFirst );
active_client->demandAttention( false );
}
pending_take_activity = NULL;
updateCurrentTopMenu();
updateToolWindows( false );
if( c )
disableGlobalShortcutsForClient( c->rules()->checkDisableGlobalShortcuts( false ));
else
disableGlobalShortcutsForClient( false );
updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
rootInfo->setActiveWindow( active_client? active_client->window() : 0 );
updateColormap();
if( effects )
static_cast<EffectsHandlerImpl*>(effects)->windowActivated( active_client ? active_client->effectWindow() : NULL );
--set_active_client_recursion;
}
/*!
Tries to activate the client \a c. This function performs what you
expect when clicking the respective entry in a taskbar: showing and
raising the client (this may imply switching to the another virtual
desktop) and putting the focus onto it. Once X really gave focus to
the client window as requested, the client itself will call
setActiveClient() and the operation is complete. This may not happen
with certain focus policies, though.
\sa stActiveClient(), requestFocus()
*/
void Workspace::activateClient( Client* c, bool force )
{
if( c == NULL )
{
setActiveClient( NULL, Allowed );
return;
}
raiseClient( c );
if (!c->isOnDesktop(currentDesktop()) )
{
++block_focus;
setCurrentDesktop( c->desktop() );
--block_focus;
}
if( c->isMinimized())
c->unminimize();
// TODO force should perhaps allow this only if the window already contains the mouse
if( options->focusPolicyIsReasonable() || force )
requestFocus( c, force );
// Don't update user time for clients that have focus stealing workaround.
// As they usually belong to the current active window but fail to provide
// this information, updating their user time would make the user time
// of the currently active window old, and reject further activation for it.
// E.g. typing URL in minicli which will show kio_uiserver dialog (with workaround),
// and then kdesktop shows dialog about SSL certificate.
// This needs also avoiding user creation time in Client::readUserTimeMapTimestamp().
if( !c->ignoreFocusStealing())
c->updateUserTime();
}
/*!
Tries to activate the client by asking X for the input focus. This
function does not perform any show, raise or desktop switching. See
Workspace::activateClient() instead.
\sa Workspace::activateClient()
*/
void Workspace::requestFocus( Client* c, bool force )
{
takeActivity( c, ActivityFocus | ( force ? ActivityFocusForce : 0 ), false);
}
void Workspace::takeActivity( Client* c, int flags, bool handled )
{
// the 'if( c == active_client ) return;' optimization mustn't be done here
if (!focusChangeEnabled() && ( c != active_client) )
flags &= ~ActivityFocus;
if ( !c )
{
focusToNull();
return;
}
if( flags & ActivityFocus )
{
Client* modal = c->findModal();
if( modal != NULL && modal != c )
{
if( !modal->isOnDesktop( c->desktop()))
{
modal->setDesktop( c->desktop());
if( modal->desktop() != c->desktop()) // forced desktop
activateClient( modal );
}
// if the click was inside the window (i.e. handled is set),
// but it has a modal, there's no need to use handled mode, because
// the modal doesn't get the click anyway
// raising of the original window needs to be still done
if( flags & ActivityRaise )
raiseClient( c );
c = modal;
handled = false;
}
cancelDelayFocus();
}
if ( !( flags & ActivityFocusForce ) && ( c->isTopMenu() || c->isDock() || c->isSplash()) )
flags &= ~ActivityFocus; // toplevel menus and dock windows don't take focus if not forced
if( c->isShade())
{
if( c->wantsInput() && ( flags & ActivityFocus ))
{
// client cannot accept focus, but at least the window should be active (window menu, et. al. )
c->setActive( true );
focusToNull();
}
flags &= ~ActivityFocus;
handled = false; // no point, can't get clicks
}
if( !c->isShown( true )) // shouldn't happen, call activateClient() if needed
{
kWarning( 1212 ) << "takeActivity: not shown" << endl;
return;
}
c->takeActivity( flags, handled, Allowed );
}
void Workspace::handleTakeActivity( Client* c, Time /*timestamp*/, int flags )
{
if( pending_take_activity != c ) // pending_take_activity is reset when doing restack or activation
return;
if(( flags & ActivityRaise ) != 0 )
raiseClient( c );
if(( flags & ActivityFocus ) != 0 && c->isShown( false ))
c->takeFocus( Allowed );
pending_take_activity = NULL;
}
/*!
Informs the workspace that the client \a c has been hidden. If it
was the active client (or to-become the active client),
the workspace activates another one.
\a c may already be destroyed
*/
void Workspace::clientHidden( Client* c )
{
assert( !c->isShown( true ) || !c->isOnCurrentDesktop());
activateNextClient( c );
}
// deactivates 'c' and activates next client
bool Workspace::activateNextClient( Client* c )
{
// if 'c' is not the active or the to-become active one, do nothing
if( !( c == active_client
|| ( should_get_focus.count() > 0 && c == should_get_focus.last())))
return false;
closeActivePopup();
if( c != NULL )
{
if( c == active_client )
setActiveClient( NULL, Allowed );
should_get_focus.removeAll( c );
}
if( focusChangeEnabled())
{
if ( options->focusPolicyIsReasonable())
{ // search the focus_chain for a client to transfer focus to
// if 'c' is transient, transfer focus to the first suitable mainwindow
Client* get_focus = NULL;
const ClientList mainwindows = ( c != NULL ? c->mainClients() : ClientList());
for ( int i = focus_chain[ currentDesktop() ].size() - 1;
i >= 0;
--i )
{
if( !focus_chain[ currentDesktop() ].at( i )->isShown( false )
|| !focus_chain[ currentDesktop() ].at( i )->isOnCurrentDesktop())
continue;
if( mainwindows.contains( focus_chain[ currentDesktop() ].at( i ) ))
{
get_focus = focus_chain[ currentDesktop() ].at( i );
break;
}
if( get_focus == NULL )
get_focus = focus_chain[ currentDesktop() ].at( i );
}
if( get_focus == NULL )
get_focus = findDesktop( true, currentDesktop());
if( get_focus != NULL )
requestFocus( get_focus );
else
focusToNull();
}
else
return false;
}
else
// if blocking focus, move focus to the desktop later if needed
// in order to avoid flickering
focusToNull();
return true;
}
void Workspace::gotFocusIn( const Client* c )
{
if( should_get_focus.contains( const_cast< Client* >( c )))
{ // remove also all sooner elements that should have got FocusIn,
// but didn't for some reason (and also won't anymore, because they were sooner)
while( should_get_focus.first() != c )
should_get_focus.pop_front();
should_get_focus.pop_front(); // remove 'c'
}
}
void Workspace::setShouldGetFocus( Client* c )
{
should_get_focus.append( c );
updateStackingOrder(); // e.g. fullscreens have different layer when active/not-active
}
// focus_in -> the window got FocusIn event
// session_active -> the window was active when saving session
bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in )
{
// options->focusStealingPreventionLevel :
// 0 - none - old KWin behaviour, new windows always get focus
// 1 - low - focus stealing prevention is applied normally, when unsure, activation is allowed
// 2 - normal - focus stealing prevention is applied normally, when unsure, activation is not allowed,
// this is the default
// 3 - high - new window gets focus only if it belongs to the active application,
// or when no window is currently active
// 4 - extreme - no window gets focus without user intervention
if( time == -1U )
time = c->userTime();
int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
if( session_saving && level <= 2 ) // <= normal
{
return true;
}
Client* ac = mostRecentlyActivatedClient();
if( focus_in )
{
if( should_get_focus.contains( const_cast< Client* >( c )))
return true; // FocusIn was result of KWin's action
// Before getting FocusIn, the active Client already
// got FocusOut, and therefore got deactivated.
ac = last_active_client;
}
if( time == 0 ) // explicitly asked not to get focus
return false;
if( level == 0 ) // none
return true;
if( level == 4 ) // extreme
return false;
if( !c->isOnCurrentDesktop())
return false; // allow only with level == 0
if( c->ignoreFocusStealing())
return true;
if( ac == NULL || ac->isDesktop())
{
kDebug( 1212 ) << "Activation: No client active, allowing" << endl;
return true; // no active client -> always allow
}
// TODO window urgency -> return true?
if( Client::belongToSameApplication( c, ac, true ))
{
kDebug( 1212 ) << "Activation: Belongs to active application" << endl;
return true;
}
if( level == 3 ) // high
return false;
if( time == -1U ) // no time known
{
kDebug( 1212 ) << "Activation: No timestamp at all" << endl;
if( level == 1 ) // low
return true;
// no timestamp at all, don't activate - because there's also creation timestamp
// done on CreateNotify, this case should happen only in case application
// maps again already used window, i.e. this won't happen after app startup
return false;
}
// level == 2 // normal
Time user_time = ac->userTime();
kDebug( 1212 ) << "Activation, compared:" << c << ":" << time << ":" << user_time
<< ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
return timestampCompare( time, user_time ) >= 0; // time >= user_time
}
// basically the same like allowClientActivation(), this time allowing
// a window to be fully raised upon its own request (XRaiseWindow),
// if refused, it will be raised only on top of windows belonging
// to the same application
bool Workspace::allowFullClientRaising( const Client* c, Time time )
{
int level = c->rules()->checkFSP( options->focusStealingPreventionLevel );
if( session_saving && level <= 2 ) // <= normal
{
return true;
}
Client* ac = mostRecentlyActivatedClient();
if( level == 0 ) // none
return true;
if( level == 4 ) // extreme
return false;
if( ac == NULL || ac->isDesktop())
{
kDebug( 1212 ) << "Raising: No client active, allowing" << endl;
return true; // no active client -> always allow
}
if( c->ignoreFocusStealing())
return true;
// TODO window urgency -> return true?
if( Client::belongToSameApplication( c, ac, true ))
{
kDebug( 1212 ) << "Raising: Belongs to active application" << endl;
return true;
}
if( level == 3 ) // high
return false;
Time user_time = ac->userTime();
kDebug( 1212 ) << "Raising, compared:" << time << ":" << user_time
<< ":" << ( timestampCompare( time, user_time ) >= 0 ) << endl;
return timestampCompare( time, user_time ) >= 0; // time >= user_time
}
// called from Client after FocusIn that wasn't initiated by KWin and the client
// wasn't allowed to activate
void Workspace::restoreFocus()
{
// this updateXTime() is necessary - as FocusIn events don't have
// a timestamp *sigh*, kwin's timestamp would be older than the timestamp
// that was used by whoever caused the focus change, and therefore
// the attempt to restore the focus would fail due to old timestamp
updateXTime();
if( should_get_focus.count() > 0 )
requestFocus( should_get_focus.last());
else if( last_active_client )
requestFocus( last_active_client );
}
void Workspace::clientAttentionChanged( Client* c, bool set )
{
if( set )
{
attention_chain.removeAll( c );
attention_chain.prepend( c );
}
else
attention_chain.removeAll( c );
}
// This is used when a client should be shown active immediately after requestFocus(),
// without waiting for the matching FocusIn that will really make the window the active one.
// Used only in special cases, e.g. for MouseActivateRaiseandMove with transparent windows,
bool Workspace::fakeRequestedActivity( Client* c )
{
if( should_get_focus.count() > 0 && should_get_focus.last() == c )
{
if( c->isActive())
return false;
c->setActive( true );
return true;
}
return false;
}
void Workspace::unfakeActivity( Client* c )
{
if( should_get_focus.count() > 0 && should_get_focus.last() == c )
{ // TODO this will cause flicker, and probably is not needed
if( last_active_client != NULL )
last_active_client->setActive( true );
else
c->setActive( false );
}
}
//********************************************
// Client
//********************************************
/*!
Updates the user time (time of last action in the active window).
This is called inside kwin for every action with the window
that qualifies for user interaction (clicking on it, activate it
externally, etc.).
*/
void Client::updateUserTime( Time time )
{ // copied in Group::updateUserTime
if( time == CurrentTime )
time = xTime();
if( time != -1U
&& ( user_time == CurrentTime
|| timestampCompare( time, user_time ) > 0 )) // time > user_time
user_time = time;
group()->updateUserTime( user_time );
}
Time Client::readUserCreationTime() const
{
long result = -1; // Time == -1 means none
Atom type;
int format, status;
unsigned long nitems = 0;
unsigned long extra = 0;
unsigned char *data = 0;
KXErrorHandler handler; // ignore errors?
status = XGetWindowProperty( display(), window(),
atoms->kde_net_wm_user_creation_time, 0, 10000, false, XA_CARDINAL,
&type, &format, &nitems, &extra, &data );
if (status == Success )
{
if (data && nitems > 0)
result = *((long*) data);
XFree(data);
}
return result;
}
void Client::demandAttention( bool set )
{
if( isActive())
set = false;
if( demands_attention == set )
return;
demands_attention = set;
if( demands_attention )
{
// Demand attention flag is often set right from manage(), when focus stealing prevention
// steps in. At that time the window has no taskbar entry yet, so KNotify cannot place
// e.g. the passive popup next to it. So wait up to 1 second for the icon geometry
// to be set.
// Delayed call to KNotify also solves the problem of having X server grab in manage(),
// which may deadlock when KNotify (or KLauncher when launching KNotify) need to access X.
// Setting the demands attention state needs to be done directly in KWin, because
// KNotify would try to set it, resulting in a call to KNotify again, etc.
info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
if( demandAttentionKNotifyTimer == NULL )
{
demandAttentionKNotifyTimer = new QTimer( this );
demandAttentionKNotifyTimer->setSingleShot( true );
connect( demandAttentionKNotifyTimer, SIGNAL( timeout()), SLOT( demandAttentionKNotify()));
}
demandAttentionKNotifyTimer->start( 1000 );
}
else
info->setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
workspace()->clientAttentionChanged( this, set );
}
void Client::demandAttentionKNotify()
{
Notify::Event e = isOnCurrentDesktop() ? Notify::DemandAttentionCurrent : Notify::DemandAttentionOther;
Notify::raise( e, i18n( "Window '%1' demands attention.", KStringHandler::csqueeze(caption())), this );
demandAttentionKNotifyTimer->stop();
demandAttentionKNotifyTimer->deleteLater();
demandAttentionKNotifyTimer = NULL;
}
// TODO I probably shouldn't be lazy here and do it without the macro, so that people can read it
KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, Client, const Client*,
// ignore already existing splashes, toolbars, utilities, menus and topmenus,
// as the app may show those before the main window
!cl->isSplash() && !cl->isToolbar() && !cl->isTopMenu() && !cl->isUtility() && !cl->isMenu()
&& Client::belongToSameApplication( cl, value, true ) && cl != value);
Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
bool session ) const
{
Time time = info->userTime();
kDebug( 1212 ) << "User timestamp, initial:" << time << endl;
// newer ASN timestamp always replaces user timestamp, unless user timestamp is 0
// helps e.g. with konqy reusing
if( asn_data != NULL && time != 0 )
{
// prefer timestamp from ASN id (timestamp from data is obsolete way)
if( asn_id->timestamp() != 0
&& ( time == -1U || timestampCompare( asn_id->timestamp(), time ) > 0 ))
{
time = asn_id->timestamp();
}
else if( asn_data->timestamp() != -1U
&& ( time == -1U || timestampCompare( asn_data->timestamp(), time ) > 0 ))
{
time = asn_data->timestamp();
}
}
kDebug( 1212 ) << "User timestamp, ASN:" << time << endl;
if( time == -1U )
{ // The window doesn't have any timestamp.
// If it's the first window for its application
// (i.e. there's no other window from the same app),
// use the _KDE_NET_WM_USER_CREATION_TIME trick.
// Otherwise, refuse activation of a window
// from already running application if this application
// is not the active one (unless focus stealing prevention is turned off).
Client* act = workspace()->mostRecentlyActivatedClient();
if( act != NULL && !belongToSameApplication( act, this, true ))
{
bool first_window = true;
if( isTransient())
{
if( act->hasTransient( this, true ))
; // is transient for currently active window, even though it's not
// the same app (e.g. kcookiejar dialog) -> allow activation
else if( groupTransient() &&
findClientInList( mainClients(), SameApplicationActiveHackPredicate( this )) == NULL )
; // standalone transient
else
first_window = false;
}
else
{
if( workspace()->findClient( SameApplicationActiveHackPredicate( this )))
first_window = false;
}
// don't refuse if focus stealing prevention is turned off
if( !first_window && rules()->checkFSP( options->focusStealingPreventionLevel ) > 0 )
{
kDebug( 1212 ) << "User timestamp, already exists:" << 0 << endl;
return 0; // refuse activation
}
}
// Creation time would just mess things up during session startup,
// as possibly many apps are started up at the same time.
// If there's no active window yet, no timestamp will be needed,
// as plain Workspace::allowClientActivation() will return true
// in such case. And if there's already active window,
// it's better not to activate the new one.
// Unless it was the active window at the time
// of session saving and there was no user interaction yet,
// this check will be done in manage().
if( session )
return -1U;
if( ignoreFocusStealing() && act != NULL )
time = act->userTime();
else
time = readUserCreationTime();
}
kDebug( 1212 ) << "User timestamp, final:" << this << ":" << time << endl;
return time;
}
Time Client::userTime() const
{
Time time = user_time;
if( time == 0 ) // doesn't want focus after showing
return 0;
assert( group() != NULL );
if( time == -1U
|| ( group()->userTime() != -1U
&& timestampCompare( group()->userTime(), time ) > 0 ))
time = group()->userTime();
return time;
}
/*!
Sets the client's active state to \a act.
This function does only change the visual appearance of the client,
it does not change the focus setting. Use
Workspace::activateClient() or Workspace::requestFocus() instead.
If a client receives or looses the focus, it calls setActive() on
its own.
*/
void Client::setActive( bool act )
{
if ( active == act )
return;
active = act;
workspace()->setActiveClient( act ? this : NULL, Allowed );
if ( active )
Notify::raise( Notify::Activate );
if( !active )
cancelAutoRaise();
if( !active && shade_mode == ShadeActivated )
setShade( ShadeNormal );
StackingUpdatesBlocker blocker( workspace());
workspace()->updateClientLayer( this ); // active windows may get different layer
// TODO optimize? mainClients() may be a bit expensive
ClientList mainclients = mainClients();
for( ClientList::ConstIterator it = mainclients.begin();
it != mainclients.end();
++it )
if( (*it)->isFullScreen()) // fullscreens go high even if their transient is active
workspace()->updateClientLayer( *it );
if( decoration != NULL )
decoration->activeChange();
updateMouseGrab();
updateUrgency(); // demand attention again if it's still urgent
}
void Client::startupIdChanged()
{
KStartupInfoId asn_id;
KStartupInfoData asn_data;
bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
if( !asn_valid )
return;
// If the ASN contains desktop, move it to the desktop, otherwise move it to the current
// desktop (since the new ASN should make the window act like if it's a new application
// launched). However don't affect the window's desktop if it's set to be on all desktops.
int desktop = workspace()->currentDesktop();
if( asn_data.desktop() != 0 )
desktop = asn_data.desktop();
if( !isOnAllDesktops())
workspace()->sendClientToDesktop( this, desktop, true );
Time timestamp = asn_id.timestamp();
if( timestamp == 0 && asn_data.timestamp() != -1U )
timestamp = asn_data.timestamp();
if( timestamp != 0 )
{
bool activate = workspace()->allowClientActivation( this, timestamp );
if( asn_data.desktop() != 0 && !isOnCurrentDesktop())
activate = false; // it was started on different desktop than current one
if( activate )
workspace()->activateClient( this );
else
demandAttention();
}
}
void Client::updateUrgency()
{
if( urgency )
demandAttention();
}
void Client::shortcutActivated()
{
workspace()->activateClient( this, true ); // force
}
//****************************************
// Group
//****************************************
void Group::startupIdChanged()
{
KStartupInfoId asn_id;
KStartupInfoData asn_data;
bool asn_valid = workspace()->checkStartupNotification( leader_wid, asn_id, asn_data );
if( !asn_valid )
return;
if( asn_id.timestamp() != 0 && user_time != -1U
&& timestampCompare( asn_id.timestamp(), user_time ) > 0 )
{
user_time = asn_id.timestamp();
}
else if( asn_data.timestamp() != -1U && user_time != -1U
&& timestampCompare( asn_data.timestamp(), user_time ) > 0 )
{
user_time = asn_data.timestamp();
}
}
void Group::updateUserTime( Time time )
{ // copy of Client::updateUserTime
if( time == CurrentTime )
time = xTime();
if( time != -1U
&& ( user_time == CurrentTime
|| timestampCompare( time, user_time ) > 0 )) // time > user_time
user_time = time;
}
} // namespace

104
atoms.cpp Normal file
View file

@ -0,0 +1,104 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#include <QApplication>
#include "atoms.h"
#include "utils.h"
#include <assert.h>
namespace KWin
{
Atoms::Atoms()
{
const int max = 50;
Atom* atoms[max];
char* names[max];
Atom atoms_return[max];
int n = 0;
atoms[n] = &kwin_running;
names[n++] = (char *) "KWIN_RUNNING";
atoms[n] = &wm_protocols;
names[n++] = (char *) "WM_PROTOCOLS";
atoms[n] = &wm_delete_window;
names[n++] = (char *) "WM_DELETE_WINDOW";
atoms[n] = &wm_take_focus;
names[n++] = (char *) "WM_TAKE_FOCUS";
atoms[n] = &wm_change_state;
names[n++] = (char *) "WM_CHANGE_STATE";
atoms[n] = &wm_client_leader;
names[n++] = (char *) "WM_CLIENT_LEADER";
atoms[n] = &wm_window_role;
names[n++] = (char *) "WM_WINDOW_ROLE";
atoms[n] = &wm_state;
names[n++] = (char *) "WM_STATE";
atoms[n] = &sm_client_id;
names[n++] = (char *) "SM_CLIENT_ID";
atoms[n] = &motif_wm_hints;
names[n++] = (char *) "_MOTIF_WM_HINTS";
atoms[n] = &net_wm_context_help;
names[n++] = (char *) "_NET_WM_CONTEXT_HELP";
atoms[n] = &net_wm_ping;
names[n++] = (char *) "_NET_WM_PING";
atoms[n] = &kde_wm_change_state;
names[n++] = (char *) "_KDE_WM_CHANGE_STATE";
atoms[n] = &net_wm_user_time;
names[n++] = (char *) "_NET_WM_USER_TIME";
atoms[n] = &kde_net_wm_user_creation_time;
names[n++] = (char *) "_KDE_NET_WM_USER_CREATION_TIME";
atoms[n] = &kde_system_tray_embedding;
names[n++] = (char*) "_KDE_SYSTEM_TRAY_EMBEDDING";
atoms[n] = &net_wm_take_activity;
names[n++] = (char*) "_NET_WM_TAKE_ACTIVITY";
atoms[n] = &net_wm_window_opacity;
names[n++] = (char*) "_NET_WM_WINDOW_OPACITY";
Atom fake;
atoms[n] = &fake;
names[n++] = (char *) "_DT_SM_WINDOW_INFO";
atoms[n] = &xdnd_aware;
names[n++] = (char*) "XdndAware";
atoms[n] = &xdnd_position;
names[n++] = (char*) "XdndPosition";
atoms[n] = &net_frame_extents;
names[n++] = (char*) "_NET_FRAME_EXTENTS";
atoms[n] = &kde_net_wm_frame_strut;
names[n++] = (char*) "_KDE_NET_WM_FRAME_STRUT";
assert( n <= max );
XInternAtoms( display(), names, n, false, atoms_return );
for (int i = 0; i < n; i++ )
*atoms[i] = atoms_return[i];
}
} // namespace

55
atoms.h Normal file
View file

@ -0,0 +1,55 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#ifndef KWIN_ATOMS_H
#define KWIN_ATOMS_H
#include <X11/Xlib.h>
namespace KWin
{
class Atoms
{
public:
Atoms();
Atom kwin_running;
Atom wm_protocols;
Atom wm_delete_window;
Atom wm_take_focus;
Atom wm_change_state;
Atom wm_client_leader;
Atom wm_window_role;
Atom wm_state;
Atom sm_client_id;
Atom motif_wm_hints;
Atom net_wm_context_help;
Atom net_wm_ping;
Atom kde_wm_change_state;
Atom net_wm_user_time;
Atom kde_net_wm_user_creation_time;
Atom kde_system_tray_embedding;
Atom net_wm_take_activity;
Atom net_wm_window_opacity;
Atom xdnd_aware;
Atom xdnd_position;
Atom net_frame_extents;
Atom kde_net_wm_frame_strut;
};
extern Atoms* atoms;
} // namespace
#endif

205
bridge.cpp Normal file
View file

@ -0,0 +1,205 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#include "bridge.h"
#include "client.h"
#include "options.h"
namespace KWin
{
Bridge::Bridge( Client* cl )
: c( cl )
{
}
#define BRIDGE_HELPER( rettype, prototype, args1, args2, cst ) \
rettype Bridge::prototype ( args1 ) cst \
{ \
return c->prototype( args2 ); \
}
BRIDGE_HELPER( bool, isActive,,, const )
BRIDGE_HELPER( bool, isCloseable,,, const )
BRIDGE_HELPER( bool, isMaximizable,,, const )
BRIDGE_HELPER( Bridge::MaximizeMode, maximizeMode,,, const )
BRIDGE_HELPER( bool, isMinimizable,,, const )
BRIDGE_HELPER( bool, providesContextHelp,,, const )
BRIDGE_HELPER( int, desktop,,, const )
BRIDGE_HELPER( bool, isModal,,, const )
BRIDGE_HELPER( bool, isShadeable,,, const )
BRIDGE_HELPER( bool, isShade,,, const )
BRIDGE_HELPER( bool, keepAbove,,, const )
BRIDGE_HELPER( bool, keepBelow,,, const )
BRIDGE_HELPER( bool, isMovable,,, const )
BRIDGE_HELPER( bool, isResizable,,, const )
BRIDGE_HELPER( QString, caption,,, const )
BRIDGE_HELPER( void, processMousePressEvent, QMouseEvent* e, e, )
BRIDGE_HELPER( QRect, geometry,,, const )
BRIDGE_HELPER( void, closeWindow,,, )
BRIDGE_HELPER( void, maximize, MaximizeMode m, m, )
BRIDGE_HELPER( void, minimize,,, )
BRIDGE_HELPER( void, showContextHelp,,, )
BRIDGE_HELPER( void, setDesktop, int desktop, desktop, )
void Bridge::setKeepAbove( bool set )
{
if( c->keepAbove() != set )
c->workspace()->performWindowOperation( c, KeepAboveOp );
}
void Bridge::setKeepBelow( bool set )
{
if( c->keepBelow() != set )
c->workspace()->performWindowOperation( c, KeepBelowOp );
}
NET::WindowType Bridge::windowType( unsigned long supported_types ) const
{
return c->windowType( false, supported_types );
}
QIcon Bridge::icon() const
{
#warning KDE4 drop me ?
return QIcon( /*c->miniIcon(),*/ c->icon());
}
bool Bridge::isSetShade() const
{
return c->shadeMode() != ShadeNone;
}
void Bridge::showWindowMenu( QPoint p )
{
c->workspace()->showWindowMenu( p, c );
}
void Bridge::showWindowMenu( const QRect &p )
{
c->workspace()->showWindowMenu( p, c );
}
void Bridge::performWindowOperation( WindowOperation op )
{
c->workspace()->performWindowOperation( c, op );
}
void Bridge::setMask( const QRegion& r, int mode )
{
c->setMask( r, mode );
}
bool Bridge::isPreview() const
{
return false;
}
QRect Bridge::iconGeometry() const
{
NETRect r = c->info->iconGeometry();
return QRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
}
QWidget* Bridge::workspaceWidget() const
{
return c->workspace()->desktopWidget();
}
WId Bridge::windowId() const
{
return c->window();
}
void Bridge::titlebarDblClickOperation()
{
c->workspace()->performWindowOperation( c, options->operationTitlebarDblClick());
}
void Bridge::titlebarMouseWheelOperation( int delta )
{
c->performMouseCommand( options->operationTitlebarMouseWheel( delta ), cursorPos());
}
void Bridge::setShade( bool set )
{
c->setShade( set ? ShadeNormal : ShadeNone );
}
int Bridge::currentDesktop() const
{
return c->workspace()->currentDesktop();
}
QWidget* Bridge::initialParentWidget() const
{
return NULL;
}
Qt::WFlags Bridge::initialWFlags() const
{
return 0;
}
void Bridge::helperShowHide( bool show )
{
if( show )
c->rawShow();
else
c->rawHide();
}
QRegion Bridge::unobscuredRegion( const QRegion& r ) const
{
QRegion reg( r );
const ClientList stacking_order = c->workspace()->stackingOrder();
int pos = stacking_order.indexOf( c );
++pos;
for(; pos < stacking_order.count(); ++pos )
{
if( !stacking_order[pos]->isShown( true ))
continue; // these don't obscure the window
if( c->isOnAllDesktops())
{
if( !stacking_order[ pos ]->isOnCurrentDesktop())
continue;
}
else
{
if( !stacking_order[ pos ]->isOnDesktop( c->desktop()))
continue;
}
/* the clients all have their mask-regions in local coords
so we have to translate them to a shared coord system
we choose ours */
int dx = stacking_order[ pos ]->x() - c->x();
int dy = stacking_order[ pos ]->y() - c->y();
QRegion creg = stacking_order[ pos ]->mask();
creg.translate(dx, dy);
reg -= creg;
if (reg.isEmpty())
{
// early out, we are completely obscured
break;
}
}
return reg;
}
void Bridge::grabXServer( bool grab )
{
if( grab )
KWin::grabXServer();
else
KWin::ungrabXServer();
}
} // namespace

75
bridge.h Normal file
View file

@ -0,0 +1,75 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#ifndef KWIN_BRIDGE_H
#define KWIN_BRIDGE_H
#include <kdecoration_p.h>
namespace KWin
{
class Client;
class Bridge : public KDecorationBridge
{
public:
Bridge( Client* cl );
virtual bool isActive() const;
virtual bool isCloseable() const;
virtual bool isMaximizable() const;
virtual MaximizeMode maximizeMode() const;
virtual bool isMinimizable() const;
virtual bool providesContextHelp() const;
virtual int desktop() const;
virtual bool isModal() const;
virtual bool isShadeable() const;
virtual bool isShade() const;
virtual bool isSetShade() const;
virtual bool keepAbove() const;
virtual bool keepBelow() const;
virtual bool isMovable() const;
virtual bool isResizable() const;
virtual NET::WindowType windowType( unsigned long supported_types ) const;
virtual QIcon icon() const;
virtual QString caption() const;
virtual void processMousePressEvent( QMouseEvent* );
virtual void showWindowMenu( QPoint );
virtual void showWindowMenu( const QRect & );
virtual void performWindowOperation( WindowOperation );
virtual void setMask( const QRegion&, int );
virtual bool isPreview() const;
virtual QRect geometry() const;
virtual QRect iconGeometry() const;
virtual QRegion unobscuredRegion( const QRegion& r ) const;
virtual QWidget* workspaceWidget() const;
virtual WId windowId() const;
virtual void closeWindow();
virtual void maximize( MaximizeMode mode );
virtual void minimize();
virtual void showContextHelp();
virtual void setDesktop( int desktop );
virtual void titlebarDblClickOperation();
virtual void titlebarMouseWheelOperation( int delta );
virtual void setShade( bool set );
virtual void setKeepAbove( bool );
virtual void setKeepBelow( bool );
virtual int currentDesktop() const;
virtual QWidget* initialParentWidget() const;
virtual Qt::WFlags initialWFlags() const;
virtual void helperShowHide( bool show );
virtual void grabXServer( bool grab );
private:
Client* c;
};
} // namespace
#endif

1504
client.cpp Normal file

File diff suppressed because it is too large Load diff

747
client.h Normal file
View file

@ -0,0 +1,747 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#ifndef KWIN_CLIENT_H
#define KWIN_CLIENT_H
#include <qframe.h>
#include <QPixmap>
#include <netwm.h>
#include <kdebug.h>
#include <assert.h>
#include <kshortcut.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <fixx11h.h>
#include "utils.h"
#include "options.h"
#include "workspace.h"
#include "kdecoration.h"
#include "rules.h"
#include "toplevel.h"
class QTimer;
class K3Process;
class KStartupInfoData;
namespace KWin
{
class Workspace;
class Client;
class SessionInfo;
class Bridge;
class Client
: public Toplevel
{
Q_OBJECT
public:
Client( Workspace *ws );
Window wrapperId() const;
Window decorationId() const;
const Client* transientFor() const;
Client* transientFor();
bool isTransient() const;
bool groupTransient() const;
bool wasOriginallyGroupTransient() const;
ClientList mainClients() const; // call once before loop , is not indirect
bool hasTransient( const Client* c, bool indirect ) const;
const ClientList& transients() const; // is not indirect
void checkTransient( Window w );
Client* findModal( bool allow_itself = false );
const Group* group() const;
Group* group();
void checkGroup( Group* gr = NULL, bool force = false );
const WindowRules* rules() const;
void removeRule( Rules* r );
void setupWindowRules( bool ignore_temporary );
void applyWindowRules();
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
// false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
bool isSpecialWindow() const;
bool hasNETSupport() const;
QSize minSize() const;
QSize maxSize() const;
QPoint clientPos() const; // inside of geometry()
QSize clientSize() const;
bool windowEvent( XEvent* e );
virtual bool eventFilter( QObject* o, QEvent* e );
bool manage( Window w, bool isMapped );
void releaseWindow( bool on_shutdown = false );
void destroyClient();
enum Sizemode // how to resize the window in order to obey constains (mainly aspect ratios)
{
SizemodeAny,
SizemodeFixedW, // try not to affect width
SizemodeFixedH, // try not to affect height
SizemodeMax // try not to make it larger in either direction
};
QSize adjustedSize( const QSize&, Sizemode mode = SizemodeAny ) const;
QSize adjustedSize() const;
QPixmap icon() const;
QPixmap miniIcon() const;
bool isActive() const;
void setActive( bool );
virtual int desktop() const;
void setDesktop( int );
void setOnAllDesktops( bool set );
// !isMinimized() && not hidden, i.e. normally visible on some virtual desktop
bool isShown( bool shaded_is_shown ) const;
bool isShade() const; // true only for ShadeNormal
ShadeMode shadeMode() const; // prefer isShade()
void setShade( ShadeMode mode );
bool isShadeable() const;
bool isMinimized() const;
bool isMaximizable() const;
QRect geometryRestore() const;
MaximizeMode maximizeModeRestore() const;
MaximizeMode maximizeMode() const;
bool isMinimizable() const;
void setMaximize( bool vertically, bool horizontally );
QRect iconGeometry() const;
void setFullScreen( bool set, bool user );
bool isFullScreen() const;
bool isFullScreenable( bool fullscreen_hack = false ) const;
bool userCanSetFullScreen() const;
QRect geometryFSRestore() const { return geom_fs_restore; } // only for session saving
int fullScreenMode() const { return fullscreen_mode; } // only for session saving
bool isUserNoBorder() const;
void setUserNoBorder( bool set );
bool userCanSetNoBorder() const;
bool noBorder() const;
bool skipTaskbar( bool from_outside = false ) const;
void setSkipTaskbar( bool set, bool from_outside );
bool skipPager() const;
void setSkipPager( bool );
bool keepAbove() const;
void setKeepAbove( bool );
bool keepBelow() const;
void setKeepBelow( bool );
Layer layer() const;
Layer belongsToLayer() const;
void invalidateLayer();
int sessionStackingOrder() const;
void setModal( bool modal );
bool isModal() const;
// auxiliary functions, depend on the windowType
bool wantsTabFocus() const;
bool wantsInput() const;
bool isResizable() const;
bool isMovable() const;
bool isCloseable() const; // may be closed by the user (may have a close button)
void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h)
void takeFocus( allowed_t );
void demandAttention( bool set = true );
void setMask( const QRegion& r, int mode = X::Unsorted );
QRegion mask() const;
void updateDecoration( bool check_workspace_pos, bool force = false );
void checkBorderSizes();
void updateShape();
void setGeometry( int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet );
void setGeometry( const QRect& r, ForceGeometry_t force = NormalGeometrySet );
void move( int x, int y, ForceGeometry_t force = NormalGeometrySet );
void move( const QPoint & p, ForceGeometry_t force = NormalGeometrySet );
// plainResize() simply resizes
void plainResize( int w, int h, ForceGeometry_t force = NormalGeometrySet );
void plainResize( const QSize& s, ForceGeometry_t force = NormalGeometrySet );
// resizeWithChecks() resizes according to gravity, and checks workarea position
void resizeWithChecks( int w, int h, ForceGeometry_t force = NormalGeometrySet );
void resizeWithChecks( const QSize& s, ForceGeometry_t force = NormalGeometrySet );
void keepInArea( QRect area, bool partial = false );
void growHorizontal();
void shrinkHorizontal();
void growVertical();
void shrinkVertical();
bool providesContextHelp() const;
KShortcut shortcut() const;
void setShortcut( const QString& cut );
bool performMouseCommand( Options::MouseCommand, QPoint globalPos, bool handled = false );
QRect adjustedClientArea( const QRect& desktop, const QRect& area ) const;
Colormap colormap() const;
// updates visibility depending on being shaded, virtual desktop, etc.
void updateVisibility();
// hides a client - basically like minimize, but without effects, it's simply hidden
void hideClient( bool hide );
QString caption( bool full = true ) const;
void updateCaption();
void keyPressEvent( uint key_code ); // FRAME ??
void updateMouseGrab();
Window moveResizeGrabWindow() const;
const QPoint calculateGravitation( bool invert, int gravity = 0 ) const; // FRAME public?
void NETMoveResize( int x_root, int y_root, NET::Direction direction );
void NETMoveResizeWindow( int flags, int x, int y, int width, int height );
void restackWindow( Window above, int detail, NET::RequestSource source, Time timestamp, bool send_event = false );
void gotPing( Time timestamp );
void checkWorkspacePosition();
void updateUserTime( Time time = CurrentTime );
Time userTime() const;
bool hasUserTimeSupport() const;
bool ignoreFocusStealing() const;
// does 'delete c;'
static void deleteClient( Client* c, allowed_t );
static bool belongToSameApplication( const Client* c1, const Client* c2, bool active_hack = false );
static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
static void readIcons( Window win, QPixmap* icon, QPixmap* miniicon );
void minimize( bool avoid_animation = false );
void unminimize( bool avoid_animation = false );
void closeWindow();
void killWindow();
void maximize( MaximizeMode );
void toggleShade();
void showContextHelp();
void cancelShadeHover();
void cancelAutoRaise();
void checkActiveModal();
bool hasStrut() const;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
private slots:
void autoRaise();
void shadeHover();
void shortcutActivated();
private:
friend class Bridge; // FRAME
virtual void processMousePressEvent( QMouseEvent* e );
private: // TODO cleanup the order of things in the .h file
// use Workspace::createClient()
virtual ~Client(); // use destroyClient() or releaseWindow()
Position mousePosition( const QPoint& ) const;
void setCursor( Position m );
void setCursor( const QCursor& c );
// transparent stuff
void drawbound( const QRect& geom );
void clearbound();
void doDrawbound( const QRect& geom, bool clear );
// handlers for X11 events
bool mapRequestEvent( XMapRequestEvent* e );
void unmapNotifyEvent( XUnmapEvent*e );
void destroyNotifyEvent( XDestroyWindowEvent*e );
void configureRequestEvent( XConfigureRequestEvent* e );
virtual void propertyNotifyEvent( XPropertyEvent* e );
void clientMessageEvent( XClientMessageEvent* e );
void enterNotifyEvent( XCrossingEvent* e );
void leaveNotifyEvent( XCrossingEvent* e );
void visibilityNotifyEvent( XVisibilityEvent* e );
void focusInEvent( XFocusInEvent* e );
void focusOutEvent( XFocusOutEvent* e );
bool buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
bool buttonReleaseEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
bool motionNotifyEvent( Window w, int state, int x, int y, int x_root, int y_root );
void processDecorationButtonPress( int button, int state, int x, int y, int x_root, int y_root );
protected:
virtual void debug( kdbgstream& stream ) const;
private slots:
void pingTimeout();
void processKillerExited();
void demandAttentionKNotify();
private:
// ICCCM 4.1.3.1, 4.1.4 , NETWM 2.5.1
void setMappingState( int s );
int mappingState() const;
bool isIconicState() const;
bool isNormalState() const;
bool isManaged() const; // returns false if this client is not yet managed
void updateAllowedActions( bool force = false );
QSize sizeForClientSize( const QSize&, Sizemode mode = SizemodeAny, bool noframe = false ) const;
void changeMaximize( bool horizontal, bool vertical, bool adjust );
void checkMaximizeGeometry();
int checkFullScreenHack( const QRect& geom ) const; // 0 - none, 1 - one xinerama screen, 2 - full area
void updateFullScreenHack( const QRect& geom );
void getWmNormalHints();
void getMotifHints();
void getIcons();
void fetchName();
void fetchIconicName();
QString readName() const;
void setCaption( const QString& s, bool force = false );
bool hasTransientInternal( const Client* c, bool indirect, ConstClientList& set ) const;
void updateWindowRules();
void finishWindowRules();
void setShortcutInternal( const KShortcut& cut );
void updateWorkareaDiffs();
void checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area );
static int computeWorkareaDiff( int left, int right, int a_left, int a_right );
void configureRequest( int value_mask, int rx, int ry, int rw, int rh, int gravity, bool from_tool );
NETExtendedStrut strut() const;
int checkShadeGeometry( int w, int h );
void blockGeometryUpdates( bool block );
bool startMoveResize();
void finishMoveResize( bool cancel );
void leaveMoveResize();
void checkUnrestrictedMoveResize();
void handleMoveResize( int x, int y, int x_root, int y_root );
void positionGeometryTip();
void grabButton( int mod );
void ungrabButton( int mod );
void resetMaximize();
void resizeDecoration( const QSize& s );
void pingWindow();
void killProcess( bool ask, Time timestamp = CurrentTime );
void updateUrgency();
static void sendClientMessage( Window w, Atom a, Atom protocol,
long data1 = 0, long data2 = 0, long data3 = 0 );
void embedClient( Window w, const XWindowAttributes &attr );
void detectNoBorder();
void destroyDecoration();
void updateFrameExtents();
void rawShow(); // just shows it
void rawHide(); // just hides it
Time readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
bool session ) const;
Time readUserCreationTime() const;
void startupIdChanged();
Window client;
Window wrapper;
KDecoration* decoration;
Bridge* bridge;
int desk;
bool buttonDown;
bool moveResizeMode;
bool move_faked_activity;
Window move_resize_grab_window;
bool move_resize_has_keyboard_grab;
bool unrestrictedMoveResize;
Position mode;
QPoint moveOffset;
QPoint invertedMoveOffset;
QRect moveResizeGeom;
QRect initialMoveResizeGeom;
XSizeHints xSizeHint;
void sendSyntheticConfigureNotify();
int mapping_state;
void readTransient();
Window verifyTransientFor( Window transient_for, bool set );
void addTransient( Client* cl );
void removeTransient( Client* cl );
void removeFromMainClients();
void cleanGrouping();
void checkGroupTransients();
void setTransient( Window new_transient_for_id );
Client* transient_for;
Window transient_for_id;
Window original_transient_for_id;
ClientList transients_list; // SELI make this ordered in stacking order?
ShadeMode shade_mode;
uint active :1;
uint deleting : 1; // true when doing cleanup and destroying the client
uint keep_above : 1; // NET::KeepAbove (was stays_on_top)
uint skip_taskbar :1;
uint original_skip_taskbar :1; // unaffected by KWin
uint Pdeletewindow :1; // does the window understand the DeleteWindow protocol?
uint Ptakefocus :1;// does the window understand the TakeFocus protocol?
uint Ptakeactivity : 1; // does it support _NET_WM_TAKE_ACTIVITY
uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol?
uint Pping : 1; // does it support _NET_WM_PING?
uint input :1; // does the window want input in its wm_hints
uint skip_pager : 1;
uint motif_noborder : 1;
uint motif_may_resize : 1;
uint motif_may_move :1;
uint motif_may_close : 1;
uint keep_below : 1; // NET::KeepBelow
uint minimized : 1;
uint hidden : 1; // forcibly hidden by calling hide()
uint modal : 1; // NET::Modal
uint noborder : 1;
uint user_noborder : 1;
uint not_obscured : 1;
uint urgency : 1; // XWMHints, UrgencyHint
uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client
uint demands_attention : 1;
WindowRules client_rules;
void getWMHints();
void readIcons();
void getWindowProtocols();
QPixmap icon_pix;
QPixmap miniicon_pix;
QCursor cursor;
// FullScreenHack - non-NETWM fullscreen (noborder,size of desktop)
// DON'T reorder - saved to config files !!!
enum FullScreenMode { FullScreenNone, FullScreenNormal, FullScreenHack };
FullScreenMode fullscreen_mode;
MaximizeMode max_mode;
QRect geom_restore;
QRect geom_fs_restore;
MaximizeMode maxmode_restore;
int workarea_diff_x, workarea_diff_y;
QTimer* autoRaiseTimer;
QTimer* shadeHoverTimer;
Colormap cmap;
QString cap_normal, cap_iconic, cap_suffix;
Group* in_group;
Window window_group;
Layer in_layer;
QTimer* ping_timer;
K3Process* process_killer;
Time ping_timestamp;
Time user_time;
unsigned long allowed_actions;
QSize client_size;
int block_geometry_updates; // >0 - new geometry is remembered, but not actually set
bool pending_geometry_update;
QRect geom_before_block;
bool shade_geometry_change;
int border_left, border_right, border_top, border_bottom;
QRegion _mask;
static bool check_active_modal; // see Client::checkActiveModal()
KShortcut _shortcut;
int sm_stacking_order;
friend struct FetchNameInternalPredicate;
friend struct CheckIgnoreFocusStealingProcedure;
friend struct ResetupRulesProcedure;
friend class GeometryUpdatesBlocker;
void show() { assert( false ); } // SELI remove after Client is no longer QWidget
void hide() { assert( false ); }
QTimer* demandAttentionKNotifyTimer;
};
// helper for Client::blockGeometryUpdates() being called in pairs (true/false)
class GeometryUpdatesBlocker
{
public:
GeometryUpdatesBlocker( Client* c )
: cl( c ) { cl->blockGeometryUpdates( true ); }
~GeometryUpdatesBlocker()
{ cl->blockGeometryUpdates( false ); }
private:
Client* cl;
};
// NET WM Protocol handler class
class WinInfo : public NETWinInfo
{
private:
typedef KWin::Client Client; // because of NET::Client
public:
WinInfo( Client* c, Display * display, Window window,
Window rwin, const unsigned long pr[], int pr_size );
virtual void changeDesktop(int desktop);
virtual void changeState( unsigned long state, unsigned long mask );
void disable();
private:
Client * m_client;
};
inline Window Client::wrapperId() const
{
return wrapper;
}
inline Window Client::decorationId() const
{
return decoration != NULL ? decoration->widget()->winId() : None;
}
inline const Client* Client::transientFor() const
{
return transient_for;
}
inline Client* Client::transientFor()
{
return transient_for;
}
inline bool Client::groupTransient() const
{
return transient_for_id == workspace()->rootWin();
}
// needed because verifyTransientFor() may set transient_for_id to root window,
// if the original value has a problem (window doesn't exist, etc.)
inline bool Client::wasOriginallyGroupTransient() const
{
return original_transient_for_id == workspace()->rootWin();
}
inline bool Client::isTransient() const
{
return transient_for_id != None;
}
inline const ClientList& Client::transients() const
{
return transients_list;
}
inline const Group* Client::group() const
{
return in_group;
}
inline Group* Client::group()
{
return in_group;
}
inline int Client::mappingState() const
{
return mapping_state;
}
inline
bool Client::isMinimized() const
{
return minimized;
}
inline bool Client::isActive() const
{
return active;
}
inline
bool Client::isShown( bool shaded_is_shown ) const
{
return !isMinimized() && ( !isShade() || shaded_is_shown ) && !hidden;
}
inline
bool Client::isShade() const
{
return shade_mode == ShadeNormal;
}
inline
ShadeMode Client::shadeMode() const
{
return shade_mode;
}
inline QPixmap Client::icon() const
{
return icon_pix;
}
inline QPixmap Client::miniIcon() const
{
return miniicon_pix;
}
inline QRect Client::geometryRestore() const
{
return geom_restore;
}
inline Client::MaximizeMode Client::maximizeModeRestore() const
{
return maxmode_restore;
}
inline Client::MaximizeMode Client::maximizeMode() const
{
return max_mode;
}
inline bool Client::skipTaskbar( bool from_outside ) const
{
return from_outside ? original_skip_taskbar : skip_taskbar;
}
inline bool Client::skipPager() const
{
return skip_pager;
}
inline bool Client::keepAbove() const
{
return keep_above;
}
inline bool Client::keepBelow() const
{
return keep_below;
}
inline bool Client::isFullScreen() const
{
return fullscreen_mode != FullScreenNone;
}
inline bool Client::isModal() const
{
return modal;
}
inline bool Client::hasNETSupport() const
{
return info->hasNETSupport();
}
inline Colormap Client::colormap() const
{
return cmap;
}
inline void Client::invalidateLayer()
{
in_layer = UnknownLayer;
}
inline int Client::sessionStackingOrder() const
{
return sm_stacking_order;
}
inline bool Client::isIconicState() const
{
return mapping_state == IconicState;
}
inline bool Client::isNormalState() const
{
return mapping_state == NormalState;
}
inline bool Client::isManaged() const
{
return mapping_state != WithdrawnState;
}
inline QPoint Client::clientPos() const
{
return QPoint( border_left, border_top );
}
inline QSize Client::clientSize() const
{
return client_size;
}
inline void Client::setGeometry( const QRect& r, ForceGeometry_t force )
{
setGeometry( r.x(), r.y(), r.width(), r.height(), force );
}
inline void Client::move( const QPoint & p, ForceGeometry_t force )
{
move( p.x(), p.y(), force );
}
inline void Client::plainResize( const QSize& s, ForceGeometry_t force )
{
plainResize( s.width(), s.height(), force );
}
inline void Client::resizeWithChecks( const QSize& s, ForceGeometry_t force )
{
resizeWithChecks( s.width(), s.height(), force );
}
inline bool Client::hasUserTimeSupport() const
{
return info->userTime() != -1U;
}
inline bool Client::ignoreFocusStealing() const
{
return ignore_focus_stealing;
}
inline const WindowRules* Client::rules() const
{
return &client_rules;
}
KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, Client, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl ));
inline Window Client::moveResizeGrabWindow() const
{
return move_resize_grab_window;
}
inline KShortcut Client::shortcut() const
{
return _shortcut;
}
inline void Client::removeRule( Rules* rule )
{
client_rules.remove( rule );
}
KWIN_COMPARE_PREDICATE( WrapperIdMatchPredicate, Client, Window, cl->wrapperId() == value );
} // namespace
#endif

10
clients/CMakeLists.txt Normal file
View file

@ -0,0 +1,10 @@
add_subdirectory( plastik )
add_subdirectory( b2 )
add_subdirectory( default )
add_subdirectory( keramik )
add_subdirectory( laptop )
add_subdirectory( modernsystem )
add_subdirectory( quartz )
add_subdirectory( redmond )
add_subdirectory( web )

3
clients/Messages.sh Normal file
View file

@ -0,0 +1,3 @@
#! /usr/bin/env bash
$EXTRACTRC `find . -name \*.ui` >> rc.cpp || exit 11
$XGETTEXT `find . -name \*.cpp` -o $podir/kwin_clients.pot

159
clients/PORTING Normal file
View file

@ -0,0 +1,159 @@
It's suggested you check sources of some KDE CVS decoration if in doubts or in need of an example.
Also, the API is documented in the .h header files.
Makefile.am:
- Change kwin_ to kwin3_ (in LDFLAGS, LIBADD, kde_module_LTLIBRARIES, SOURCES).
- Make sure LDFLAGS contains $(KDE_PLUGIN) and -module .
- Add -lkdecorations to LIBADD.
- Do NOT rename the directory where the .desktop file is installed ( $(kde_datadir)/kwin/ ).
.desktop file:
- Change kwin_ to kwin3_ in X-KDE-Library.
Sources:
- There are no kwin/something.h includes, and don't use the KWinInternal namespace.
- Use QToolTip instead of KWinToolTip.
- Use QButton instead of KWinButton, QToolButton instead of KWinToolButton and QWidget
instead of KWinWidgetButton.
- For tooltips, use simply QToolTip::add().
- Change Client* to MyClient* (or whatever is your main client class) in your MyButton.
- Pass parent->widget() to QButton constructor in your MyButton constructor.
- Make your MyClient class inherit from KDecoration instead of Client.
- Make MyClient constructor take KDecorationBridge* and KDecorationFactory* as arguments,
and pass these arguments to KDecoration constructor.
- Except for data members initialization, make the constructor empty, move everything
to void MyClient::init().
- As the first thing in init(), call createMainWidget(); if your client class took some
flags such as WResizeNoErase, pass them to this function.
- Then, do 'widget()->installEventFilter( this );'.
- Implement MyClient::eventFilter() - as MyClient is now no longer QWidget, you need the event
filter to call all the functions that used to be called directly. Usually, it's something
like:
=====
bool MyClient::eventFilter( QObject* o, QEvent* e )
{
if ( o != widget() )
return false;
switch ( e->type() )
{
case QEvent::Resize:
resizeEvent( static_cast< QResizeEvent* >( e ) );
return true;
case QEvent::Paint:
paintEvent( static_cast< QPaintEvent* >( e ) );
return true;
case QEvent::MouseButtonDblClick:
mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) );
return true;
case QEvent::Wheel:
wheelEvent( static_cast< QWheelEvent* >( e ));
return true;
case QEvent::MouseButtonPress:
processMousePressEvent( static_cast< QMouseEvent* >( e ) );
return true;
case QEvent::Show:
showEvent( static_cast< QShowEvent* >( e ) );
return true;
default:
return false;
}
}
=====
- In MyClient, 'this' will have to be often replaced with 'widget()', pay special attention
to cases where this won't cause compile error (e.g. in connect() calls, which take QObject* ).
- Also, many calls may need 'widget()->' prepended.
- Layout is created in init(), so call createLayout() directly there (if it's implemented).
- Remove calls to Client methods (Client::resizeEvent() and so on).
- Replace Options:: with KDecorationOptions:: .
- Replace 'options' with 'options()' in MyClient (which is KDecoration::options()), if often used
outside of MyClient, you may want to create (this assumes your code is in its namespace):
=====
inline const KDecorationOptions* options() { return KDecoration::options(); }
=====
- Options for colors need 'Color' prepended (e.g. 'ColorButtonBg').
- Replace miniIcon() with getting the right pixmap from icon() (usually
'icon().pixmap( QIcon::Small, QIcon::Normal )' ).
- Replace stickyChange() with desktopChange(), and test isOnAllDesktops().
- Replace Sticky with OnAllDestops.
- Replace iconify with minimize.
- Change activeChange(bool) to activeChange(), and use isActive() to check the state.
Similar for desktopChange, captionChange(), iconChange(), maximizeChange().
- Replace 'contextHelp()' with 'showContextHelp()'.
- WindowWrapperShowEvent() is gone, simply use showEvent() filtered by the event filter if needed.
- Change 'animateIconifyOrDeiconify()' to 'animateMinize()', if it's empty, simply remove it.
Make sure it doesn't reenter the event loop (no kapp->processEvents()).
- Buttons should use explicit setCursor() if they don't want cursor set by mousePosition().
I.e. usually call setCursor( ArrowCursor ) in your MyButton.
- In the part where you insert windowWrapper() into the layout, i.e. something like
=====
layout->addWidget( windowWrapper());
=====
replace it with something like
=====
if( isPreview())
layout->addWidget( new QLabel( i18n( "<center><b>MyDecoration</b></center>" ), widget()));
else
layout->addItem( new QSpacerItem( 0, 0 ));
=====
- Implement MyClient::minimumSize().
- Handling maximization - to change vertical or horizontal maximalization, use e.g.
'maximize( maximizeMode() ^ MaximizeVertical', to change normal maximalization, i.e. after
left-clicking on the button, use
'maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull );' (which also
means that there's also no maximize() slot).
Also, if your decoration button has only two visual states representing the maximalization state,
it's recommended that it shows the maximized state only for MaximizeFull state.
- Make sure the decoration matches the window state after init() is finished, that is, that
the buttons represent correctly the maximalization, on-all-desktops etc. states. As the
simplest solution, you can call maximizeChange(), desktopChange(), etc. at the end
of init().
- Use 'titlebarDblClickOperation()' for performing the application after doubleclicking
the titlebar.
- Implement borders() returning the width of the top,left,right and bottom border. You may
check values like 'maximizeMode() == MaximizeFull && !options()->moveResizeMaximizedWindows()'
to check whether you can disable some borders completely.
Note that your painting code must of course match these sizes.
- If your code uses XGrabServer() or XUnGrabServer(), replace them with (un)grabXServer().
- In cases where you call some function from the KDecoration API that can possibly destroy
the decoration (e.g. showWindowMenu() or closeWindow()), make sure to use exists() if some more
code will follow this call. Refer to showWindowMenu() documentation for an example.
- Create class MyFactory inheriting from KDecorationFactory, and move the code that was
in 'extern "C"' to it: From init() to constructor, from deinit() to destructor, from allocate()
or create() to createDecoration(). Pass the KDecorationBridge* argument and 'this' to created
MyClient objects. If createDecoration() needs to know the window type (e.g. it used the tool
argument), use windowType() similarly like in KDecoration, and pass it the KDecorationBridge*
argument.
- Add something like this:
=====
extern "C"
{
KDecorationFactory *create_factory()
{
return new MyNamespace::MyFactory();
}
}
=====
- The reset handling has changed: There's no signal resetClients(), and no
slotResetAllClientsDelayed(). If your MyClient has some slotReset(), make it
reset( unsigned long ), where the argument is mask of things that have changed ( SettingXYZ ).
If you have some global function that handles resetting, make it
MyFactory::reset( unsigned long ). Try to minimize the effects of the changed things,
e.g. if only the color setting has changed, doing a repaint is often enough, and there's no need
to recreate the decorations. If you need to recreate the decorations, return true
from MyFactory::reset(), otherwise, you may call resetDecorations() to call reset() in all
MyClient instances.
- Implement resize() to resize the decoration to the given size
(usually 'widget()->resize( s );' is enough).
- Review mousePosition() if it's implemented. Position constants need 'Position' prepended,
e.g. Top -> PositionTop.
- Note that you cannot use "appdata" with KStandardDirs, as the decoration will be used
also in other applications than kwin.
- Implement all missing pure virtual functions. For mousePosition(), you may call
KDecoration::mousePosition() if it's sufficient.

View file

@ -0,0 +1,20 @@
If you are looking to include a C++ KWin style client in CVS make sure you
follow the following requirements:
A) You must follow the current color scheme for all decorations. *No* fixed
pixmaps are allowed for the clients. If you wish to draw your decorations
use as few shades as possible, then use kpixmap2bitmap in kdegraphics
to convert them into individual bitmaps. Once this is done you can
draw the bitmaps using a colorgroup with kColorBitmaps.
If your client is just a set of pixmaps that doesn't follow any of the options
I suggest you make a KWM theme so the user gets those options to
configure the pixmaps and look. Making a plain pixmapped dedicated style
makes no sense since it is less configurable than KWM themes and cannot follow
client plugin options.
B) You must follow at least the color settings in the Options class.
Daniel M. Duley
mosfet@kde.org

25
clients/b2/CMakeLists.txt Normal file
View file

@ -0,0 +1,25 @@
add_subdirectory( config )
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin3_b2_PART_SRCS b2client.cpp )
kde4_automoc(kwin3_b2 ${kwin3_b2_PART_SRCS})
kde4_add_plugin(kwin3_b2 ${kwin3_b2_PART_SRCS})
kde4_install_libtool_file( ${PLUGIN_INSTALL_DIR} kwin3_b2 )
target_link_libraries(kwin3_b2 ${KDE4_KDEUI_LIBS} kdecorations kdefx ${QT_QT3SUPPORT_LIBRARY} ${X11_LIBRARIES} ${QT_QTGUI_LIBRARY})
install(TARGETS kwin3_b2 DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES b2.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin/ )

5
clients/b2/b2.desktop Normal file
View file

@ -0,0 +1,5 @@
[Desktop Entry]
Encoding=UTF-8
Name=B II
Name[x-test]=xxB IIxx
X-KDE-Library=kwin3_b2

1441
clients/b2/b2client.cpp Normal file

File diff suppressed because it is too large Load diff

173
clients/b2/b2client.h Normal file
View file

@ -0,0 +1,173 @@
/*
* B-II KWin Client
*
* Changes:
* Customizable button positions by Karol Szwed <gallium@kde.org>
* Ported to the kde3.2 API by Luciano Montanaro <mikelima@cirulla.net>
*/
#ifndef __B2CLIENT_H
#define __B2CLIENT_H
#include <QVariant>
#include <QDateTime>
#include <q3button.h>
#include <QBitmap>
//Added by qt3to4:
#include <QPaintEvent>
#include <QGridLayout>
#include <QEvent>
#include <QBoxLayout>
#include <QShowEvent>
#include <QResizeEvent>
#include <QMouseEvent>
#include <QPixmap>
#include <kdecoration.h>
#include <kdecorationfactory.h>
class QSpacerItem;
class QBoxLayout;
class QGridLayout;
namespace B2 {
class B2Client;
class B2Button : public Q3Button
{
public:
B2Button(B2Client *_client=0, QWidget *parent=0, const QString& tip=NULL, const int realizeBtns = Qt::LeftButton);
~B2Button() {};
void setBg(const QColor &c){bg = c;}
void setPixmaps(QPixmap *pix, QPixmap *pixDown, QPixmap *iPix,
QPixmap *iPixDown);
void setPixmaps(int button_id);
void setToggle(){setCheckable(true);}
void setActive(bool on){setChecked(on);}
void setUseMiniIcon(){useMiniIcon = true;}
QSize sizeHint() const;
QSizePolicy sizePolicy() const;
protected:
virtual void drawButton(QPainter *p);
void drawButtonLabel(QPainter *){;}
void mousePressEvent( QMouseEvent* e );
void mouseReleaseEvent( QMouseEvent* e );
private:
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
bool useMiniIcon;
QPixmap *icon[6];
QColor bg; //only use one color (the rest is pixmap) so forget QPalette ;)
public:
B2Client* client;
Qt::MouseButtons last_button;
int realizeButtons;
bool hover;
};
class B2Titlebar : public QWidget
{
friend class B2Client;
public:
B2Titlebar(B2Client *parent);
~B2Titlebar(){;}
bool isFullyObscured() const {return isfullyobscured;}
void recalcBuffer();
QSpacerItem *captionSpacer;
protected:
void paintEvent( QPaintEvent* );
bool x11Event(XEvent *e);
void mouseDoubleClickEvent( QMouseEvent * );
void mousePressEvent( QMouseEvent * );
void mouseReleaseEvent( QMouseEvent * );
void mouseMoveEvent(QMouseEvent *);
void resizeEvent(QResizeEvent *ev);
private:
void drawTitlebar(QPainter &p, bool state);
B2Client *client;
QString oldTitle;
QPixmap titleBuffer;
QPoint moveOffset;
bool set_x11mask;
bool isfullyobscured;
bool shift_move;
};
class B2Client : public KDecoration
{
Q_OBJECT
friend class B2Titlebar;
public:
B2Client(KDecorationBridge *b, KDecorationFactory *f);
~B2Client(){;}
void init();
void unobscureTitlebar();
void titleMoveAbs(int new_ofs);
void titleMoveRel(int xdiff);
// transparent stuff
virtual bool drawbound(const QRect& geom, bool clear);
protected:
void resizeEvent( QResizeEvent* );
void paintEvent( QPaintEvent* );
void showEvent( QShowEvent* );
void windowWrapperShowEvent( QShowEvent* );
void captionChange();
void desktopChange();
void shadeChange();
void activeChange();
void maximizeChange();
void iconChange();
void doShape();
Position mousePosition( const QPoint& p ) const;
void resize(const QSize&);
void borders(int &, int &, int &, int &) const;
QSize minimumSize() const;
bool eventFilter(QObject *, QEvent *);
private slots:
void menuButtonPressed();
//void slotReset();
void maxButtonClicked();
void shadeButtonClicked();
void resizeButtonPressed();
private:
void addButtons(const QString& s, const QString tips[],
B2Titlebar* tb, QBoxLayout* titleLayout);
void positionButtons();
void calcHiddenButtons();
bool mustDrawHandle() const;
enum ButtonType{BtnMenu=0, BtnSticky, BtnIconify, BtnMax, BtnClose,
BtnHelp, BtnShade, BtnResize, BtnCount};
B2Button* button[BtnCount];
QGridLayout *g;
// Border spacers
QSpacerItem *topSpacer;
QSpacerItem *bottomSpacer;
QSpacerItem *leftSpacer;
QSpacerItem *rightSpacer;
B2Titlebar *titlebar;
int bar_x_ofs;
int in_unobs;
QTime time;
bool resizable;
};
class B2ClientFactory : public QObject, public KDecorationFactory
{
public:
B2ClientFactory();
virtual ~B2ClientFactory();
virtual KDecoration *createDecoration(KDecorationBridge *);
virtual bool reset(unsigned long changed);
virtual bool supports( Ability ability );
QList< B2ClientFactory::BorderSize > borderSizes() const;
};
}
#endif

98
clients/b2/bitmaps.h Normal file
View file

@ -0,0 +1,98 @@
#ifndef __STDCLIENT_BITMAPS_H
#define __STDCLIENT_BITMAPS_H
/**
* The standard client has the capability to color it's titlebar buttons
* according to the new color scheme. In order to do this it needs a bitmap
* for each shade which it draws into a pixmap with the appropriate color.
* These are all the bitmaps.
*/
static const unsigned char close_white_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x04, 0x08, 0x08, 0x04, 0x10, 0x02,
0x20, 0x01, 0x40, 0x00, 0x40, 0x00, 0x20, 0x01, 0x10, 0x02, 0x08, 0x04,
0x04, 0x08, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00};
static const unsigned char close_dgray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x18, 0x30, 0x30, 0x18, 0x60, 0x0c,
0xc0, 0x06, 0x80, 0x03, 0x80, 0x03, 0xc0, 0x06, 0x60, 0x0c, 0x30, 0x18,
0x18, 0x30, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00};
static const unsigned char menu_white_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfc, 0x3f, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char menu_dgray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char menu_mask_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfc, 0x3f, 0x04, 0x20, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pindown_white_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03,
0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pindown_gray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pindown_dgray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20,
0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e,
0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pindown_mask_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xf0, 0x3f, 0xf0, 0x3f,
0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x0f,
0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_white_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11,
0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_gray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_dgray_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e,
0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char pinup_mask_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0xc0, 0x31, 0xc0, 0x3f,
0xff, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xc0, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char help_mask_bits[] = {
0x00,0x00,0x00,0x00,0xe0,0x03,0xf0,0x07,0x70,0x0e,0x60,0x0e,0x00,0x0f,0x80,
0x07,0xc0,0x03,0xc0,0x01,0x80,0x01,0xc0,0x00,0xc0,0x01,0x80,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x4c,0x0b,0x08,0x58,0x65,0x09,0x08,0x90,0x00,0x00,
0x00,0x09,0x04,0x00,0x00,0x72,0x6f,0x6f,0x74,0x00,0x24,0x31,0x24,0x47,0x6b,
0x65,0x44,0x78,0x63 };
static const unsigned char help_dark_bits[] = {
0x00,0x00,0x00,0x00,0xe0,0x03,0x30,0x06,0x30,0x06,0x00,0x06,0x00,0x03,0x80,
0x01,0xc0,0x00,0xc0,0x00,0x00,0x00,0xc0,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x65,0x64,0x28,0x29,0x00,0x00,0x00,0x00,0x90,0x00,0x00,
0x00,0x21,0x00,0x00,0x00,0x34,0xfe,0x12,0x2b,0x00,0x00,0xff,0xff,0x58,0xc0,
0x01,0x2b,0x45,0xfe };
static const unsigned char help_light_bits[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,0x40,0x08,0x60,0x08,0x00,0x0c,0x00,
0x06,0x00,0x03,0x00,0x01,0x80,0x01,0x00,0x00,0x00,0x01,0x80,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x4c,0x0b,0x08,0x58,0x65,0x09,0x08,0x90,0x00,0x00,
0x00,0x09,0x04,0x00,0x00,0x72,0x6f,0x6f,0x74,0x00,0x24,0x31,0x24,0x47,0x6b,
0x65,0x44,0x78,0x63 };
#endif

View file

@ -0,0 +1,18 @@
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin_b2_config_PART_SRCS config.cpp )
kde4_automoc(kwin_b2_config ${kwin_b2_config_PART_SRCS})
kde4_add_plugin(kwin_b2_config ${kwin_b2_config_PART_SRCS})
target_link_libraries(kwin_b2_config ${KDE4_KDEUI_LIBS} ${QT_QT3SUPPORT_LIBRARY} ${QT_QTGUI_LIBRARY})
install(TARGETS kwin_b2_config DESTINATION ${PLUGIN_INSTALL_DIR} )

View file

@ -0,0 +1,169 @@
/*
* This file contains the B2 configuration widget
*
* Copyright (c) 2001
* Karol Szwed <gallium@kde.org>
* http://gallium.n3.net/
*/
#include "config.h"
#include <kglobal.h>
//Added by qt3to4:
#include <QLabel>
#include <klocale.h>
#include <kvbox.h>
extern "C"
{
KDE_EXPORT QObject* allocate_config( KConfig* conf, QWidget* parent )
{
return(new B2Config(conf, parent));
}
}
/* NOTE:
* 'conf' is a pointer to the kwindecoration modules open kwin config,
* and is by default set to the "Style" group.
*
* 'parent' is the parent of the QObject, which is a VBox inside the
* Configure tab in kwindecoration
*/
B2Config::B2Config( KConfig* conf, QWidget* parent )
: QObject( parent )
{
KGlobal::locale()->insertCatalog("kwin_b2_config");
b2Config = new KConfig("kwinb2rc");
gb = new KVBox(parent);
cbColorBorder = new QCheckBox(
i18n("Draw window frames using &titlebar colors"), gb);
cbColorBorder->setWhatsThis(
i18n("When selected, the window borders "
"are drawn using the titlebar colors; otherwise, they are "
"drawn using normal border colors."));
// Grab Handle
showGrabHandleCb = new QCheckBox(
i18n("Draw &resize handle"), gb);
showGrabHandleCb->setWhatsThis(
i18n("When selected, decorations are drawn with a \"grab handle\" "
"in the bottom right corner of the windows; "
"otherwise, no grab handle is drawn."));
// Double click menu option support
actionsGB = new Q3GroupBox(i18n("Actions Settings"), gb);
actionsGB->setOrientation(Qt::Horizontal);
QLabel *menuDblClickLabel = new QLabel(actionsGB);
menuDblClickLabel->setText(i18n("Double click on menu button:"));
menuDblClickOp = new QComboBox(actionsGB);
menuDblClickOp->addItem(i18n("Do Nothing"));
menuDblClickOp->addItem(i18n("Minimize Window"));
menuDblClickOp->addItem(i18n("Shade Window"));
menuDblClickOp->addItem(i18n("Close Window"));
menuDblClickOp->setWhatsThis(
i18n("An action can be associated to a double click "
"of the menu button. Leave it to none if in doubt."));
// Load configuration options
load(conf);
// Ensure we track user changes properly
connect(cbColorBorder, SIGNAL(clicked()),
this, SLOT(slotSelectionChanged()));
connect(showGrabHandleCb, SIGNAL(clicked()),
this, SLOT(slotSelectionChanged()));
connect(menuDblClickOp, SIGNAL(activated(int)),
this, SLOT(slotSelectionChanged()));
// Make the widgets visible in kwindecoration
gb->show();
}
B2Config::~B2Config()
{
delete b2Config;
delete gb;
}
void B2Config::slotSelectionChanged()
{
emit changed();
}
// Loads the configurable options from the kwinrc config file
// It is passed the open config from kwindecoration to improve efficiency
void B2Config::load(KConfig * /*conf*/)
{
KConfigGroup cg(b2Config, "General");
bool override = cg.readEntry("UseTitleBarBorderColors", false);
cbColorBorder->setChecked(override);
override = cg.readEntry( "DrawGrabHandle", true);
showGrabHandleCb->setChecked(override);
QString returnString = cg.readEntry(
"MenuButtonDoubleClickOperation", "NoOp");
int op;
if (returnString == "Close") {
op = 3;
} else if (returnString == "Shade") {
op = 2;
} else if (returnString == "Minimize") {
op = 1;
} else {
op = 0;
}
menuDblClickOp->setCurrentIndex(op);
}
static QString opToString(int op)
{
switch (op) {
case 1:
return "Minimize";
case 2:
return "Shade";
case 3:
return "Close";
case 0:
default:
return "NoOp";
}
}
// Saves the configurable options to the kwinrc config file
void B2Config::save(KConfig * /*conf*/)
{
KConfigGroup cg(b2Config, "General");
cg.writeEntry("UseTitleBarBorderColors", cbColorBorder->isChecked());
cg.writeEntry("DrawGrabHandle", showGrabHandleCb->isChecked());
cg.writeEntry("MenuButtonDoubleClickOperation",
opToString(menuDblClickOp->currentIndex()));
// Ensure others trying to read this config get updated
b2Config->sync();
}
// Sets UI widget defaults which must correspond to style defaults
void B2Config::defaults()
{
cbColorBorder->setChecked(false);
showGrabHandleCb->setChecked(true);
menuDblClickOp->setCurrentIndex(0);
}
#include "config.moc"
// vim: ts=4

View file

@ -0,0 +1,49 @@
/*
* This file contains the B2 configuration widget
*
* Copyright (c) 2001
* Karol Szwed <gallium@kde.org>
* http://gallium.n3.net/
*/
#ifndef _KDE_B2CONFIG_H
#define _KDE_B2CONFIG_H
#include <QCheckBox>
#include <q3groupbox.h>
#include <QLabel>
#include <QComboBox>
#include <kconfig.h>
class B2Config: public QObject
{
Q_OBJECT
public:
B2Config( KConfig* conf, QWidget* parent );
~B2Config();
// These public signals/slots work similar to KCM modules
signals:
void changed();
public slots:
void load( KConfig* conf );
void save( KConfig* conf );
void defaults();
protected slots:
void slotSelectionChanged(); // Internal use
private:
KConfig* b2Config;
QCheckBox* cbColorBorder;
QCheckBox* showGrabHandleCb;
Q3GroupBox* actionsGB;
QComboBox* menuDblClickOp;
QWidget* gb;
};
#endif
// vim: ts=4

View file

@ -0,0 +1,19 @@
add_subdirectory( config )
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin3_default_PART_SRCS kdedefault.cpp )
kde4_automoc(kwin3_default ${kwin3_default_PART_SRCS})
kde4_add_plugin(kwin3_default ${kwin3_default_PART_SRCS})
target_link_libraries(kwin3_default ${KDE4_KDECORE_LIBS} kdefx kdecorations ${QT_QTGUI_LIBRARY})
install(TARGETS kwin3_default DESTINATION ${PLUGIN_INSTALL_DIR} )

View file

@ -0,0 +1,17 @@
########### next target ###############
set(kwin_default_config_PART_SRCS config.cpp )
kde4_automoc(kwin_default_config ${kwin_default_config_PART_SRCS})
kde4_add_plugin(kwin_default_config ${kwin_default_config_PART_SRCS})
target_link_libraries(kwin_default_config ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY})
install(TARGETS kwin_default_config DESTINATION ${PLUGIN_INSTALL_DIR} )

View file

@ -0,0 +1,131 @@
/*
*
* KDE2 Default configuration widget
*
* Copyright (c) 2001
* Karol Szwed <gallium@kde.org>
* http://gallium.n3.net/
*/
#include "config.h"
#include <kglobal.h>
#include <QWhatsThis>
#include <kdialog.h>
#include <klocale.h>
#include <QPixmap>
#include <kvbox.h>
extern "C"
{
KDE_EXPORT QObject* allocate_config( KConfig* conf, QWidget* parent )
{
return(new KDEDefaultConfig(conf, parent));
}
}
// NOTE:
// 'conf' is a pointer to the kwindecoration modules open kwin config,
// and is by default set to the "Style" group.
// 'parent' is the parent of the QObject, which is a VBox inside the
// Configure tab in kwindecoration
KDEDefaultConfig::KDEDefaultConfig( KConfig* conf, QWidget* parent )
: QObject( parent )
{
KGlobal::locale()->insertCatalog("kwin_clients");
highcolor = QPixmap::defaultDepth() > 8;
gb = new KVBox( parent );
gb->setSpacing( KDialog::spacingHint() );
cbShowStipple = new QCheckBox( i18n("Draw titlebar &stipple effect"), gb );
cbShowStipple->setWhatsThis(
i18n("When selected, active titlebars are drawn "
"with a stipple (dotted) effect; otherwise, they are "
"drawn without the stipple."));
cbShowGrabBar = new QCheckBox( i18n("Draw g&rab bar below windows"), gb );
cbShowGrabBar->setWhatsThis(
i18n("When selected, decorations are drawn with a \"grab bar\" "
"below windows; otherwise, no grab bar is drawn."));
// Only show the gradient checkbox for highcolor displays
if (highcolor)
{
cbUseGradients = new QCheckBox( i18n("Draw &gradients"), gb );
cbUseGradients->setWhatsThis(
i18n("When selected, decorations are drawn with gradients "
"for high-color displays; otherwise, no gradients are drawn.") );
}
// Load configuration options
load( conf );
// Ensure we track user changes properly
connect( cbShowStipple, SIGNAL(clicked()),
this, SLOT(slotSelectionChanged()) );
connect( cbShowGrabBar, SIGNAL(clicked()),
this, SLOT(slotSelectionChanged()) );
if (highcolor)
connect( cbUseGradients, SIGNAL(clicked()),
this, SLOT(slotSelectionChanged()) );
// Make the widgets visible in kwindecoration
gb->show();
}
KDEDefaultConfig::~KDEDefaultConfig()
{
delete gb;
}
void KDEDefaultConfig::slotSelectionChanged()
{
emit changed();
}
// Loads the configurable options from the kwinrc config file
// It is passed the open config from kwindecoration to improve efficiency
void KDEDefaultConfig::load( KConfig* conf )
{
KConfigGroup cg(conf, "KDEDefault");
bool override = cg.readEntry( "ShowTitleBarStipple", true);
cbShowStipple->setChecked( override );
override = cg.readEntry( "ShowGrabBar", true);
cbShowGrabBar->setChecked( override );
if (highcolor) {
override = cg.readEntry( "UseGradients", true);
cbUseGradients->setChecked( override );
}
}
// Saves the configurable options to the kwinrc config file
void KDEDefaultConfig::save( KConfig* conf )
{
KConfigGroup cg(conf, "KDEDefault");
cg.writeEntry( "ShowTitleBarStipple", cbShowStipple->isChecked() );
cg.writeEntry( "ShowGrabBar", cbShowGrabBar->isChecked() );
if (highcolor)
cg.writeEntry( "UseGradients", cbUseGradients->isChecked() );
// No need to conf->sync() - kwindecoration will do it for us
}
// Sets UI widget defaults which must correspond to style defaults
void KDEDefaultConfig::defaults()
{
cbShowStipple->setChecked( true );
cbShowGrabBar->setChecked( true );
if (highcolor)
cbUseGradients->setChecked( true );
}
#include "config.moc"
// vim: ts=4

View file

@ -0,0 +1,48 @@
/*
*
* KDE2 Default configuration widget
*
* Copyright (c) 2001
* Karol Szwed <gallium@kde.org>
* http://gallium.n3.net/
*/
#ifndef _KDE_DEFAULT_CONFIG_H
#define _KDE_DEFAULT_CONFIG_H
#include <QCheckBox>
#include <QGroupBox>
#include <kconfig.h>
#include <QLabel>
#include <kvbox.h>
class KDEDefaultConfig: public QObject
{
Q_OBJECT
public:
KDEDefaultConfig( KConfig* conf, QWidget* parent );
~KDEDefaultConfig();
// These public signals/slots work similar to KCM modules
signals:
void changed();
public slots:
void load( KConfig* conf );
void save( KConfig* conf );
void defaults();
protected slots:
void slotSelectionChanged(); // Internal use
private:
QCheckBox* cbShowStipple;
QCheckBox* cbShowGrabBar;
QCheckBox* cbUseGradients;
KVBox* gb;
bool highcolor;
};
#endif
// vim: ts=4

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,103 @@
/*
*
* KDE2 Default KWin client
*
* Copyright (C) 1999, 2001 Daniel Duley <mosfet@kde.org>
* Matthias Ettrich <ettrich@kde.org>
* Karol Szwed <gallium@kde.org>
*
* Draws mini titlebars for tool windows.
* Many features are now customizable.
*/
#ifndef _KDE_DEFAULT_H
#define _KDE_DEFAULT_H
#include <QBitmap>
#include <QDateTime>
#include <kcommondecoration.h>
#include <kdecorationfactory.h>
class QSpacerItem;
class QBoxLayout;
class QGridLayout;
class QPixmap;
namespace Default {
class KDEDefaultClient;
class KDEDefaultHandler: public KDecorationFactory
{
public:
KDEDefaultHandler();
~KDEDefaultHandler();
KDecoration* createDecoration( KDecorationBridge* b );
bool reset( unsigned long changed );
virtual QList< BorderSize > borderSizes() const;
virtual bool supports( Ability ability );
private:
unsigned long readConfig( bool update );
void createPixmaps();
void freePixmaps();
void drawButtonBackground(QPixmap *pix,
const QPalette &g, bool sunken);
};
// class KDEDefaultButton : public QButton, public KDecorationDefines
class KDEDefaultButton : public KCommonDecorationButton
{
public:
KDEDefaultButton(ButtonType type, KDEDefaultClient *parent, const char *name);
~KDEDefaultButton();
void reset(unsigned long changed);
void setBitmap(const unsigned char *bitmap);
protected:
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
void paintEvent(QPaintEvent *);
void drawButton(QPainter *p);
void drawButtonLabel(QPainter*) {;}
QBitmap* deco;
bool large;
bool isMouseOver;
};
class KDEDefaultClient : public KCommonDecoration
{
public:
KDEDefaultClient( KDecorationBridge* b, KDecorationFactory* f );
~KDEDefaultClient() {;}
virtual QString visibleName() const;
virtual QString defaultButtonsLeft() const;
virtual QString defaultButtonsRight() const;
virtual bool decorationBehaviour(DecorationBehaviour behaviour) const;
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
virtual KCommonDecorationButton *createButton(ButtonType type);
virtual QRegion cornerShape(WindowCorner corner);
void init();
void reset( unsigned long changed );
protected:
void paintEvent( QPaintEvent* );
private:
bool mustDrawHandle() const;
int titleHeight;
};
}
#endif
// vim: ts=4
// kate: space-indent off; tab-width 4;

View file

@ -0,0 +1,26 @@
add_subdirectory( config )
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin3_keramik_PART_SRCS keramik.cpp )
kde4_automoc(kwin3_keramik ${kwin3_keramik_PART_SRCS})
qt4_add_resources(kwin3_keramik_PART_SRCS tiles.qrc )
kde4_add_plugin(kwin3_keramik ${kwin3_keramik_PART_SRCS})
target_link_libraries(kwin3_keramik ${KDE4_KDEUI_LIBS} kdecorations ${QT_QT3SUPPORT_LIBRARY} ${QT_QTGUI_LIBRARY})
install(TARGETS kwin3_keramik DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES keramik.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )

View file

@ -0,0 +1,19 @@
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin_keramik_config_PART_SRCS config.cpp )
kde4_automoc(kwin_keramik_config ${kwin_keramik_config_PART_SRCS})
kde4_add_ui3_files(kwin_keramik_config_PART_SRCS keramikconfig.ui )
kde4_add_plugin(kwin_keramik_config ${kwin_keramik_config_PART_SRCS})
target_link_libraries(kwin_keramik_config ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY})
install(TARGETS kwin_keramik_config DESTINATION ${PLUGIN_INSTALL_DIR} )

View file

@ -0,0 +1,110 @@
/*
*
* Keramik KWin client configuration module
*
* Copyright (C) 2002 Fredrik Höglund <fredrik@kde.org>
*
* Based on the Quartz configuration module,
* Copyright (c) 2001 Karol Szwed <gallium@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the license, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <kglobal.h>
#include <klocale.h>
#include <QCheckBox>
#include "config.h"
#include "config.moc"
extern "C"
{
KDE_EXPORT QObject* allocate_config( KConfig* conf, QWidget* parent )
{
return ( new KeramikConfig( conf, parent ) );
}
}
/* NOTE:
* 'conf' is a pointer to the kwindecoration modules open kwin config,
* and is by default set to the "Style" group.
*
* 'parent' is the parent of the QObject, which is a VBox inside the
* Configure tab in kwindecoration
*/
KeramikConfig::KeramikConfig( KConfig* conf, QWidget* parent )
: QObject( parent )
{
KGlobal::locale()->insertCatalog("kwin_clients");
c = new KConfig( "kwinkeramikrc" );
ui = new KeramikConfigUI( parent );
connect( ui->showAppIcons, SIGNAL(clicked()), SIGNAL(changed()) );
connect( ui->smallCaptions, SIGNAL(clicked()), SIGNAL(changed()) );
connect( ui->largeGrabBars, SIGNAL(clicked()), SIGNAL(changed()) );
connect( ui->useShadowedText, SIGNAL(clicked()), SIGNAL(changed()) );
load( conf );
ui->show();
}
KeramikConfig::~KeramikConfig()
{
delete ui;
delete c;
}
// Loads the configurable options from the kwinrc config file
// It is passed the open config from kwindecoration to improve efficiency
void KeramikConfig::load( KConfig* )
{
KConfigGroup cg(c, "General");
ui->showAppIcons->setChecked( cg.readEntry("ShowAppIcons", true) );
ui->smallCaptions->setChecked( cg.readEntry("SmallCaptionBubbles", false) );
ui->largeGrabBars->setChecked( cg.readEntry("LargeGrabBars", true) );
ui->useShadowedText->setChecked( cg.readEntry("UseShadowedText", true) );
}
// Saves the configurable options to the kwinrc config file
void KeramikConfig::save( KConfig* )
{
KConfigGroup cg(c, "General");
cg.writeEntry( "ShowAppIcons", ui->showAppIcons->isChecked() );
cg.writeEntry( "SmallCaptionBubbles", ui->smallCaptions->isChecked() );
cg.writeEntry( "LargeGrabBars", ui->largeGrabBars->isChecked() );
cg.writeEntry( "UseShadowedText", ui->useShadowedText->isChecked() );
c->sync();
}
// Sets UI widget defaults which must correspond to style defaults
void KeramikConfig::defaults()
{
ui->showAppIcons->setChecked( true );
ui->smallCaptions->setChecked( false );
ui->largeGrabBars->setChecked( true );
ui->useShadowedText->setChecked( true );
emit changed();
}
// vim: set noet ts=4 sw=4:

View file

@ -0,0 +1,57 @@
/*
* Keramik KWin client configuration module
*
* Copyright (C) 2002 Fredrik Höglund <fredrik@kde.org>
*
* Based on the Quartz configuration module,
* Copyright (c) 2001 Karol Szwed <gallium@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the license, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __KWIN_KERAMIK_CONFIG_H
#define __KWIN_KERAMIK_CONFIG_H
#include <kconfig.h>
#include "keramikconfig.h"
class KeramikConfig: public QObject
{
Q_OBJECT
public:
KeramikConfig( KConfig* conf, QWidget* parent );
~KeramikConfig();
// These public signals/slots work similar to KCM modules
signals:
void changed();
public slots:
void load( KConfig* conf );
void save( KConfig* conf );
void defaults();
private:
KeramikConfigUI *ui;
KConfig *c;
};
#endif
// vim: set noet ts=4 sw=4:

View file

@ -0,0 +1,72 @@
<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
<class>KeramikConfigUI</class>
<widget class="QWidget">
<property name="name">
<cstring>KeramikConfigUI</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>287</width>
<height>102</height>
</rect>
</property>
<property name="windowTitle">
<string>Keramik</string>
</property>
<vbox>
<property name="margin">
<cstring>0</cstring>
</property>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QCheckBox">
<property name="name">
<cstring>showAppIcons</cstring>
</property>
<property name="text">
<string>Display the window &amp;icon in the caption bubble</string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if you want the window icon to be displayed in the caption bubble next to the titlebar text.</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>smallCaptions</cstring>
</property>
<property name="text">
<string>Draw &amp;small caption bubbles on active windows</string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if you want the caption bubble to have the same size on active windows that it has on inactive ones. This option is useful for laptops or low resolution displays where you want maximize the amount of space available to the window contents.</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>largeGrabBars</cstring>
</property>
<property name="text">
<string>Draw g&amp;rab bars below windows</string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if you want a grab bar to be drawn below windows. When this option is not selected only a thin border will be drawn in its place.</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>useShadowedText</cstring>
</property>
<property name="text">
<string>Use shadowed &amp;text</string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if you want the titlebar text to have a 3D look with a shadow behind it.</string>
</property>
</widget>
</vbox>
</widget>
<layoutdefaults spacing="6" margin="11"/>
</UI>

1830
clients/keramik/keramik.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,6 @@
[Desktop Entry]
Encoding=UTF-8
Name=Keramik
Name[x-test]=xxKeramikxx
X-KDE-Library=kwin3_keramik

197
clients/keramik/keramik.h Normal file
View file

@ -0,0 +1,197 @@
/*
*
* Keramik KWin client (version 0.8)
*
* Copyright (C) 2002 Fredrik Höglund <fredrik@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the license, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __KERAMIK_H
#define __KERAMIK_H
#include <Q3Button>
#include <kdecoration.h>
#include <kdecorationfactory.h>
class QSpacerItem;
namespace Keramik {
enum TilePixmap { TitleLeft=0, TitleCenter, TitleRight,
CaptionSmallLeft, CaptionSmallCenter, CaptionSmallRight,
CaptionLargeLeft, CaptionLargeCenter, CaptionLargeRight,
GrabBarLeft, GrabBarCenter, GrabBarRight,
BorderLeft, BorderRight, NumTiles };
enum Button { MenuButton=0, OnAllDesktopsButton, HelpButton, MinButton,
MaxButton, CloseButton, AboveButton, BelowButton, ShadeButton,
NumButtons };
enum ButtonDeco { Menu=0, OnAllDesktops, NotOnAllDesktops, Help, Minimize, Maximize,
Restore, Close, AboveOn, AboveOff, BelowOn, BelowOff, ShadeOn, ShadeOff,
NumButtonDecos };
struct SettingsCache
{
bool largeGrabBars:1;
bool smallCaptionBubbles:1;
};
class KeramikHandler : public KDecorationFactory
{
public:
KeramikHandler();
~KeramikHandler();
virtual QList< BorderSize > borderSizes() const;
virtual bool reset( unsigned long changed );
virtual KDecoration* createDecoration( KDecorationBridge* );
virtual bool supports( Ability ability );
bool showAppIcons() const { return showIcons; }
bool useShadowedText() const { return shadowedText; }
bool largeCaptionBubbles() const { return !smallCaptionBubbles; }
int titleBarHeight( bool large ) const {
return ( large ? activeTiles[CaptionLargeCenter]->height()
: activeTiles[CaptionSmallCenter]->height() );
}
int grabBarHeight() const
{ return activeTiles[GrabBarCenter]->height(); }
const QPixmap *roundButton() const { return titleButtonRound; }
const QPixmap *squareButton() const { return titleButtonSquare; }
const QBitmap *buttonDeco( ButtonDeco deco ) const
{ return buttonDecos[ deco ]; }
inline const QPixmap *tile( TilePixmap tilePix, bool active ) const;
private:
void readConfig();
void createPixmaps();
void destroyPixmaps();
void addWidth (int width, QPixmap *&pix, bool left, QPixmap *bottomPix);
void addHeight (int height, QPixmap *&pix);
void flip( QPixmap *&, QPixmap *& );
void pretile( QPixmap *&, int, Qt::Orientation );
QPixmap *composite( QImage *, QImage * );
QImage *loadImage( const QString &, const QColor & );
QPixmap *loadPixmap( const QString &, const QColor & );
bool showIcons:1, shadowedText:1,
smallCaptionBubbles:1, largeGrabBars:1;
SettingsCache *settings_cache;
QPixmap *activeTiles[ NumTiles ];
QPixmap *inactiveTiles[ NumTiles ];
QBitmap *buttonDecos[ NumButtonDecos ];
QPixmap *titleButtonRound, *titleButtonSquare;
}; // class KeramikHandler
class KeramikClient;
class KeramikButton : public Q3Button
{
public:
KeramikButton( KeramikClient *, const char *, Button, const QString &, const int realizeBtns = Qt::LeftButton );
~KeramikButton();
Qt::MouseButtons lastButton() const { return lastbutton; }
private:
void enterEvent( QEvent * );
void leaveEvent( QEvent * );
void mousePressEvent( QMouseEvent * );
void mouseReleaseEvent( QMouseEvent * );
void drawButton( QPainter * );
private:
KeramikClient *client;
Button button;
bool hover;
Qt::MouseButtons lastbutton;
int realizeButtons;
}; // class KeramikButton
class KeramikClient : public KDecoration
{
Q_OBJECT
public:
KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory );
~KeramikClient();
virtual void init();
virtual void reset( unsigned long changed );
virtual Position mousePosition( const QPoint& p ) const;
virtual void borders( int& left, int& right, int& top, int& bottom ) const;
virtual void resize( const QSize& s );
virtual QSize minimumSize() const;
virtual bool eventFilter( QObject* o, QEvent* e );
virtual void activeChange();
virtual void captionChange();
virtual void maximizeChange();
virtual void desktopChange();
virtual void shadeChange();
private:
void createLayout();
void addButtons( QBoxLayout*, const QString & );
void updateMask(); // FRAME
void updateCaptionBuffer();
void iconChange();
void resizeEvent( QResizeEvent *); // FRAME
void paintEvent( QPaintEvent *); // FRAME
void mouseDoubleClickEvent( QMouseEvent * ); // FRAME
int width() const { return widget()->width(); }
int height() const { return widget()->height(); }
void calculateCaptionRect();
inline bool maximizedVertical() const {
return ( maximizeMode() & MaximizeVertical );
}
private slots:
void menuButtonPressed();
void slotMaximize();
void slotAbove();
void slotBelow();
void slotShade();
void keepAboveChange( bool );
void keepBelowChange( bool );
private:
QSpacerItem *topSpacer, *titlebar;
KeramikButton *button[ NumButtons ];
QRect captionRect;
QPixmap captionBuffer;
QPixmap *activeIcon, *inactiveIcon;
bool captionBufferDirty:1, maskDirty:1;
bool largeCaption:1, largeTitlebar:1;
}; // class KeramikClient
} // namespace Keramik
#endif // ___KERAMIK_H
// vim: set noet ts=4 sw=4:

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

27
clients/keramik/tiles.qrc Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>pics/border-left.png</file>
<file>pics/border-right.png</file>
<file>pics/bottom-center.png</file>
<file>pics/bottom-left.png</file>
<file>pics/bottom-right.png</file>
<file>pics/caption-large-center.png</file>
<file>pics/caption-large-left.png</file>
<file>pics/caption-large-right.png</file>
<file>pics/caption-small-center.png</file>
<file>pics/caption-small-left.png</file>
<file>pics/caption-small-right.png</file>
<file>pics/grabbar-center.png</file>
<file>pics/grabbar-left.png</file>
<file>pics/grabbar-right.png</file>
<file>pics/titlebar-center.png</file>
<file>pics/titlebar-left.png</file>
<file>pics/titlebar-right.png</file>
<file>pics/titlebutton-round-huge.png</file>
<file>pics/titlebutton-round-large.png</file>
<file>pics/titlebutton-round.png</file>
<file>pics/titlebutton-square-huge.png</file>
<file>pics/titlebutton-square-large.png</file>
<file>pics/titlebutton-square.png</file>
</qresource>
</RCC>

View file

@ -0,0 +1,25 @@
add_subdirectory( cli_installer )
########### next target ###############
set(kwin3_kwmtheme_PART_SRCS kwmthemeclient.cpp )
kde4_automoc(kwin3_kwmtheme ${kwin3_kwmtheme_PART_SRCS})
kde4_add_plugin(kwin3_kwmtheme ${kwin3_kwmtheme_PART_SRCS})
target_link_libraries(kwin3_kwmtheme ${KDE4_KDECORE_LIBS} kdecorations )
install(TARGETS kwin3_kwmtheme DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES kwmtheme.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )

View file

@ -0,0 +1,15 @@
########### next target ###############
set(kwmtheme_SRCS main.cpp )
kde4_automoc(kwmtheme ${kwmtheme_SRCS})
kde4_add_executable(kwmtheme ${kwmtheme_SRCS})
target_link_libraries(kwmtheme ${KDE4_KDECORE_LIBS} )
install(TARGETS kwmtheme DESTINATION ${BIN_INSTALL_DIR})

View file

@ -0,0 +1,166 @@
#include <QFile>
#include <QDir>
#include <kapplication.h>
#include <ksimpleconfig.h>
#include <kglobal.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <kcmdlineargs.h>
#include <klocale.h>
static const char description[] =
I18N_NOOP("Installs a KWM theme");
static KCmdLineOptions options[] =
{
{ "+[file]", I18N_NOOP("Path to a theme config file"), 0 },
KCmdLineLastOption
};
void copy(const QString &src, const QString &dest)
{
QFile copyInput(src);
QFile copyOutput(dest);
if(!copyInput.open(QIODevice::ReadOnly)){
kWarning() << "Couldn't open " << src << endl;
return;
}
if(!copyOutput.open(QIODevice::WriteOnly)){
kWarning() << "Couldn't open " << dest << endl;
copyInput.close();
return;
}
while(!copyInput.atEnd()){
copyOutput.putch(copyInput.getch());
}
copyInput.close();
copyOutput.close();
}
int main(int argc, char **argv)
{
KCmdLineArgs::init(argc, argv, "kwmtheme", description, "0.1");
KCmdLineArgs::addCmdLineOptions( options );
KApplication app(argc, argv);
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
if(!args->count()){
kWarning() << "You need to specify the path to a theme config file!" << endl;
return(1);
}
QString srcStr = QString(QFile::decodeName(args->arg(0)));
QFile f(srcStr);
QString tmpStr;
if(!f.exists()){
kWarning() << "Specified theme config file doesn't exist!" << endl;
return(2);
}
QStringList appDirs = KGlobal::dirs()->findDirs("data", "kwin");
QString localDirStr = *(appDirs.end());
if(localDirStr.isEmpty()){
localDirStr = KGlobal::dirs()->saveLocation("data", "kwin");
}
localDirStr += "/pics/";
if(!QFile::exists(localDirStr))
QDir().mkdir(localDirStr);
QFileInfo fi(f);
KSimpleConfig input(fi.absoluteFilePath());
srcStr = fi.dirPath(true) + '/';
KSharedConfig::Ptr output = KGlobal::config();
input.setGroup("Window Border");
output->setGroup("General");
tmpStr = input.readEntry("shapePixmapTop");
if(!tmpStr.isEmpty()){
copy(srcStr+tmpStr, localDirStr+tmpStr);
}
output->writeEntry("wm_top", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("shapePixmapBottom");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("wm_bottom", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("shapePixmapLeft");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("wm_left", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("shapePixmapRight");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("wm_right", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("shapePixmapTopLeft");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("wm_topleft", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("shapePixmapTopRight");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("wm_topright", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("shapePixmapBottomLeft");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("wm_bottomleft", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("shapePixmapBottomRight");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("wm_bottomright", tmpStr, KConfigBase::Normal|KConfigBase::Global);
input.setGroup("Window Titlebar");
output->writeEntry("TitleAlignment", input.readEntry("TitleAlignment"), KConfigBase::Normal|KConfigBase::Global);
output->writeEntry("PixmapUnderTitleText", input.readEntry("PixmapUnderTitleText"), KConfigBase::Normal|KConfigBase::Global);
output->writeEntry("TitleFrameShaded", input.readEntry("TitleFrameShaded"), KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("MenuButton");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("menu", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("PinUpButton");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("pinup", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("PinDownButton");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("pindown", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("CloseButton");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("close", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("MaximizeButton");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("maximize", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("MaximizeDownButton");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("maximizedown", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("MinimizeButton");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("iconify", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("TitlebarPixmapActive");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("TitlebarPixmapActive", tmpStr, KConfigBase::Normal|KConfigBase::Global);
tmpStr = input.readEntry("TitlebarPixmapInactive");
if(!tmpStr.isEmpty())
copy(srcStr+tmpStr, localDirStr+tmpStr);
output->writeEntry("TitlebarPixmapInactive", tmpStr, KConfigBase::Normal|KConfigBase::Global);
input.setGroup("Window Button Layout");
output->setGroup("Buttons");
output->writeEntry("ButtonA", input.readEntry("ButtonA"), KConfigBase::Normal|KConfigBase::Global);
output->writeEntry("ButtonB", input.readEntry("ButtonB"), KConfigBase::Normal|KConfigBase::Global);
output->writeEntry("ButtonC", input.readEntry("ButtonC"), KConfigBase::Normal|KConfigBase::Global);
output->writeEntry("ButtonD", input.readEntry("ButtonD"), KConfigBase::Normal|KConfigBase::Global);
output->writeEntry("ButtonE", input.readEntry("ButtonE"), KConfigBase::Normal|KConfigBase::Global);
output->writeEntry("ButtonF", input.readEntry("ButtonF"), KConfigBase::Normal|KConfigBase::Global);
output->sync();
return(0);
}

View file

@ -0,0 +1,6 @@
[Desktop Entry]
Encoding=UTF-8
Name=KWM Theme
Name[fr]=Thème KWM
Name[x-test]=xxKWM Themexx
X-KDE-Library=kwin3_kwmtheme

View file

@ -0,0 +1,935 @@
#include <kconfig.h>
#include "kwmthemeclient.h"
#include <kglobal.h>
#include <QLayout>
#include <qdrawutil.h>
#include <QPainter>
#include <kpixmapeffect.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <klocale.h>
#include <QBitmap>
#include <QStyle>
#include <QLabel>
namespace KWMTheme {
/* static QPixmap stretchPixmap(QPixmap& src, bool stretchVert){
QPixmap dest;
QBitmap *srcMask, *destMask;
int w, h, w2, h2;
QPainter p;
if (src.isNull()) return src;
w = src.width();
h = src.height();
if (stretchVert){
w2 = w;
for (h2=h; h2<100; h2=h2<<1)
;
}
else{
h2 = h;
for (w2=w; w2<100; w2=w2<<1)
;
}
if (w2==w && h2==h) return src;
dest = src;
dest.resize(w2, h2);
p.begin(&dest);
p.drawTiledPixmap(0, 0, w2, h2, src);
p.end();
srcMask = (QBitmap*)src.mask();
if (srcMask){
destMask = (QBitmap*)dest.mask();
p.begin(destMask);
p.drawTiledPixmap(0, 0, w2, h2, *srcMask);
p.end();
}
return dest;
} */
inline const KDecorationOptions* options() { return KDecoration::options(); }
enum FramePixmap{FrameTop=0, FrameBottom, FrameLeft, FrameRight, FrameTopLeft,
FrameTopRight, FrameBottomLeft, FrameBottomRight};
static QPixmap *framePixmaps[8];
static QPixmap *menuPix, *iconifyPix, *closePix, *maxPix, *minmaxPix,
*pinupPix, *pindownPix;
static QPixmap *aTitlePix = 0;
static QPixmap *iTitlePix = 0;
static KPixmapEffect::GradientType grType;
static int maxExtent, titleAlign;
static bool titleGradient = true;
static bool pixmaps_created = false;
static bool titleSunken = false;
static bool titleTransparent;
static void create_pixmaps()
{
const char *keys[] = {"wm_top", "wm_bottom", "wm_left", "wm_right",
"wm_topleft", "wm_topright", "wm_bottomleft", "wm_bottomright"};
if(pixmaps_created)
return;
pixmaps_created = true;
KSharedConfig::Ptr _config = KGlobal::config();
KConfigGroup config(_config, "General");
QString tmpStr;
for(int i=0; i < 8; ++i)
{
framePixmaps[i] = new QPixmap(locate("data",
"kwin/pics/"+config.readEntry(keys[i], " ")));
if(framePixmaps[i]->isNull())
kWarning() << "Unable to load frame pixmap for " << keys[i] << endl;
}
/*
*framePixmaps[FrameTop] = stretchPixmap(*framePixmaps[FrameTop], false);
*framePixmaps[FrameBottom] = stretchPixmap(*framePixmaps[FrameBottom], false);
*framePixmaps[FrameLeft] = stretchPixmap(*framePixmaps[FrameLeft], true);
*framePixmaps[FrameRight] = stretchPixmap(*framePixmaps[FrameRight], true);
*/
maxExtent = framePixmaps[FrameTop]->height();
if(framePixmaps[FrameBottom]->height() > maxExtent)
maxExtent = framePixmaps[FrameBottom]->height();
if(framePixmaps[FrameLeft]->width() > maxExtent)
maxExtent = framePixmaps[FrameLeft]->width();
if(framePixmaps[FrameRight]->width() > maxExtent)
maxExtent = framePixmaps[FrameRight]->width();
maxExtent++;
menuPix = new QPixmap(locate("data",
"kwin/pics/"+config.readEntry("menu", " ")));
iconifyPix = new QPixmap(locate("data",
"kwin/pics/"+config.readEntry("iconify", " ")));
maxPix = new QPixmap(locate("appdata",
"pics/"+config.readEntry("maximize", " ")));
minmaxPix = new QPixmap(locate("data",
"kwin/pics/"+config.readEntry("maximizedown", " ")));
closePix = new QPixmap(locate("data",
"kwin/pics/"+config.readEntry("close", " ")));
pinupPix = new QPixmap(locate("data",
"kwin/pics/"+config.readEntry("pinup", " ")));
pindownPix = new QPixmap(locate("data",
"kwin/pics/"+config.readEntry("pindown", " ")));
if(menuPix->isNull())
menuPix->load(locate("data", "kwin/pics/menu.png"));
if(iconifyPix->isNull())
iconifyPix->load(locate("data", "kwin/pics/iconify.png"));
if(maxPix->isNull())
maxPix->load(locate("data", "kwin/pics/maximize.png"));
if(minmaxPix->isNull())
minmaxPix->load(locate("data", "kwin/pics/maximizedown.png"));
if(closePix->isNull())
closePix->load(locate("data", "kwin/pics/close.png"));
if(pinupPix->isNull())
pinupPix->load(locate("data", "kwin/pics/pinup.png"));
if(pindownPix->isNull())
pindownPix->load(locate("data", "kwin/pics/pindown.png"));
tmpStr = config.readEntry("TitleAlignment");
if(tmpStr == "right")
titleAlign = Qt::AlignRight | Qt::AlignVCenter;
else if(tmpStr == "middle")
titleAlign = Qt::AlignCenter;
else
titleAlign = Qt::AlignLeft | Qt::AlignVCenter;
titleSunken = config.readEntry("TitleFrameShaded", QVariant(true)).toBool();
// titleSunken = true; // is this fixed?
titleTransparent = config.readEntry("PixmapUnderTitleText", QVariant(true)).toBool();
tmpStr = config.readEntry("TitlebarLook");
if(tmpStr == "shadedVertical"){
aTitlePix = new QPixmap;
aTitlePix->resize(32, 20);
KPixmapEffect::gradient(*aTitlePix,
options()->color(KDecorationOptions::ColorTitleBar, true),
options()->color(KDecorationOptions::ColorTitleBlend, true),
KPixmapEffect::VerticalGradient);
iTitlePix = new QPixmap;
iTitlePix->resize(32, 20);
KPixmapEffect::gradient(*iTitlePix,
options()->color(KDecorationOptions::ColorTitleBar, false),
options()->color(KDecorationOptions::ColorTitleBlend, false),
KPixmapEffect::VerticalGradient);
titleGradient = false; // we can just tile this
}
else if(tmpStr == "shadedHorizontal")
grType = KPixmapEffect::HorizontalGradient;
else if(tmpStr == "shadedDiagonal")
grType = KPixmapEffect::DiagonalGradient;
else if(tmpStr == "shadedCrossDiagonal")
grType = KPixmapEffect::CrossDiagonalGradient;
else if(tmpStr == "shadedPyramid")
grType = KPixmapEffect::PyramidGradient;
else if(tmpStr == "shadedRectangle")
grType = KPixmapEffect::RectangleGradient;
else if(tmpStr == "shadedPipeCross")
grType = KPixmapEffect::PipeCrossGradient;
else if(tmpStr == "shadedElliptic")
grType = KPixmapEffect::EllipticGradient;
else{
titleGradient = false;
tmpStr = config.readEntry("TitlebarPixmapActive", "");
if(!tmpStr.isEmpty()){
aTitlePix = new QPixmap;
aTitlePix->load(locate("data", "kwin/pics/" + tmpStr));
}
else
aTitlePix = NULL;
tmpStr = config.readEntry("TitlebarPixmapInactive", "");
if(!tmpStr.isEmpty()){
iTitlePix = new QPixmap;
iTitlePix->load(locate("data", "kwin/pics/" + tmpStr));
}
else
iTitlePix = NULL;
}
}
static void delete_pixmaps()
{
for(int i=0; i < 8; ++i)
delete framePixmaps[i];
delete menuPix;
delete iconifyPix;
delete closePix;
delete maxPix;
delete minmaxPix;
delete pinupPix;
delete pindownPix;
delete aTitlePix;
aTitlePix = 0;
delete iTitlePix;
iTitlePix = 0;
titleGradient = true;
pixmaps_created = false;
titleSunken = false;
}
void MyButton::drawButtonLabel(QPainter *p)
{
if(pixmap()){
// If we have a theme who's button covers the entire width or
// entire height, we shift down/right by 1 pixel so we have
// some visual notification of button presses. i.e. for MGBriezh
int offset = (isDown() && ((pixmap()->width() >= width()) ||
(pixmap()->height() >= height()))) ? 1 : 0;
style().drawItem(p, QRect( offset, offset, width(), height() ),
AlignCenter, colorGroup(),
true, pixmap(), QString());
}
}
KWMThemeClient::KWMThemeClient( KDecorationBridge* b, KDecorationFactory* f )
: KDecoration( b, f )
{
}
void KWMThemeClient::init()
{
createMainWidget( WResizeNoErase | WStaticContents );
widget()->installEventFilter( this );
stickyBtn = maxBtn = mnuBtn = 0;
layout = new QGridLayout(widget());
layout->addColSpacing(0, maxExtent);
layout->addColSpacing(2, maxExtent);
layout->addRowSpacing(0, maxExtent);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed,
QSizePolicy::Expanding));
if( isPreview())
layout->addWidget( new QLabel( i18n( "<center><b>KWMTheme</b></center>" ), widget()), 2, 1);
else
layout->addItem( new QSpacerItem( 0, 0 ), 2, 1);
// Without the next line, shading flickers
layout->addItem( new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding) );
layout->addRowSpacing(3, maxExtent);
layout->setRowStretch(2, 10);
layout->setColumnStretch(1, 10);
QBoxLayout* hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0);
layout->addLayout( hb, 1, 1 );
KSharedConfig::Ptr _config = KGlobal::config();
KConfigGroup config(_config, "Buttons");
QString val;
MyButton *btn;
int i;
static const char *defaultButtons[]={"Menu","Sticky","Off","Iconify",
"Maximize","Close"};
static const char keyOffsets[]={"ABCDEF"};
for(i=0; i < 6; ++i){
if(i == 3){
titlebar = new QSpacerItem(10, 20, QSizePolicy::Expanding,
QSizePolicy::Minimum );
hb->addItem( titlebar );
}
QString key("Button");
key += QChar(keyOffsets[i]);
val = config.readEntry(key, defaultButtons[i]);
if(val == "Menu"){
mnuBtn = new MyButton(widget(), "menu");
mnuBtn->setToolTip( i18n("Menu"));
iconChange();
hb->addWidget(mnuBtn);
mnuBtn->setFixedSize(20, 20);
connect(mnuBtn, SIGNAL(pressed()), this,
SLOT(menuButtonPressed()));
}
else if(val == "Sticky"){
stickyBtn = new MyButton(widget(), "sticky");
stickyBtn->setToolTip( i18n("Sticky"));
if (isOnAllDesktops())
stickyBtn->setPixmap(*pindownPix);
else
stickyBtn->setPixmap(*pinupPix);
connect(stickyBtn, SIGNAL( clicked() ), this, SLOT(toggleOnAllDesktops()));
hb->addWidget(stickyBtn);
stickyBtn->setFixedSize(20, 20);
}
else if((val == "Iconify") && isMinimizable()){
btn = new MyButton(widget(), "iconify");
btn->setToolTip( i18n("Minimize"));
btn->setPixmap(*iconifyPix);
connect(btn, SIGNAL(clicked()), this, SLOT(minimize()));
hb->addWidget(btn);
btn->setFixedSize(20, 20);
}
else if((val == "Maximize") && isMaximizable()){
maxBtn = new MyButton(widget(), "max");
maxBtn->setToolTip( i18n("Maximize"));
maxBtn->setPixmap(*maxPix);
connect(maxBtn, SIGNAL(clicked()), this, SLOT(maximize()));
hb->addWidget(maxBtn);
maxBtn->setFixedSize(20, 20);
}
else if((val == "Close") && isCloseable()){
btn = new MyButton(widget(), "close");
btn->setToolTip( i18n("Close"));
btn->setPixmap(*closePix);
connect(btn, SIGNAL(clicked()), this, SLOT(closeWindow()));
hb->addWidget(btn);
btn->setFixedSize(20, 20);
}
else{
if((val != "Off") &&
((val == "Iconify") && !isMinimizable()) &&
((val == "Maximize") && !isMaximizable()))
kWarning() << "KWin: Unrecognized button value: " << val << endl;
}
}
if(titleGradient){
aGradient = new QPixmap;
iGradient = new QPixmap;
}
else{
aGradient = 0;
iGradient = 0;
}
widget()->setBackgroundMode(NoBackground);
}
void KWMThemeClient::drawTitle(QPainter &dest)
{
QRect titleRect = titlebar->geometry();
QRect r(0, 0, titleRect.width(), titleRect.height());
QPixmap buffer;
if(buffer.width() == r.width())
return;
buffer.resize(r.size());
QPainter p;
p.begin(&buffer);
if(titleSunken){
qDrawShadeRect(&p, r, options()->palette(KDecorationOptions::ColorFrame, isActive()).active(),
true, 1, 0);
r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
}
QPixmap *fill = isActive() ? aTitlePix : iTitlePix;
if(fill)
p.drawTiledPixmap(r, *fill);
else if(titleGradient){
fill = isActive() ? aGradient : iGradient;
if(fill->width() != r.width()){
fill->resize(r.width(), 20);
KPixmapEffect::gradient(*fill,
options()->color(KDecorationOptions::ColorTitleBar, isActive()),
options()->color(KDecorationOptions::ColorTitleBlend, isActive()),
grType);
}
p.drawTiledPixmap(r, *fill);
}
else{
p.fillRect(r, options()->palette(KDecorationOptions::ColorTitleBar, isActive()).active().
brush(QPalette::Button));
}
p.setFont(options()->font(isActive()));
p.setPen(options()->color(KDecorationOptions::ColorFont, isActive()));
// Add left & right margin
r.setLeft(r.left()+5);
r.setRight(r.right()-5);
p.drawText(r, titleAlign, caption());
p.end();
dest.drawPixmap(titleRect.x(), titleRect.y(), buffer);
}
void KWMThemeClient::resizeEvent( QResizeEvent* )
{
doShape();
widget()->repaint();
}
void KWMThemeClient::captionChange()
{
widget()->repaint( titlebar->geometry(), false );
}
void KWMThemeClient::paintEvent( QPaintEvent *)
{
QPainter p;
p.begin(widget());
int x,y;
// first the corners
int w1 = framePixmaps[FrameTopLeft]->width();
int h1 = framePixmaps[FrameTopLeft]->height();
if (w1 > width()/2) w1 = width()/2;
if (h1 > height()/2) h1 = height()/2;
p.drawPixmap(0,0,*framePixmaps[FrameTopLeft],
0,0,w1, h1);
int w2 = framePixmaps[FrameTopRight]->width();
int h2 = framePixmaps[FrameTopRight]->height();
if (w2 > width()/2) w2 = width()/2;
if (h2 > height()/2) h2 = height()/2;
p.drawPixmap(width()-w2,0,*framePixmaps[FrameTopRight],
framePixmaps[FrameTopRight]->width()-w2,0,w2, h2);
int w3 = framePixmaps[FrameBottomLeft]->width();
int h3 = framePixmaps[FrameBottomLeft]->height();
if (w3 > width()/2) w3 = width()/2;
if (h3 > height()/2) h3 = height()/2;
p.drawPixmap(0,height()-h3,*framePixmaps[FrameBottomLeft],
0,framePixmaps[FrameBottomLeft]->height()-h3,w3, h3);
int w4 = framePixmaps[FrameBottomRight]->width();
int h4 = framePixmaps[FrameBottomRight]->height();
if (w4 > width()/2) w4 = width()/2;
if (h4 > height()/2) h4 = height()/2;
p.drawPixmap(width()-w4,height()-h4,*(framePixmaps[FrameBottomRight]),
framePixmaps[FrameBottomRight]->width()-w4,
framePixmaps[FrameBottomRight]->height()-h4,
w4, h4);
QPixmap pm;
QMatrix m;
int n,s,w;
//top
pm = *framePixmaps[FrameTop];
if (pm.width() > 0){
s = width()-w2-w1;
n = s/pm.width();
w = n>0?s/n:s;
m.reset();
m.scale(w/(float)pm.width(), 1);
pm = pm.transformed(m);
x = w1;
while (1){
if (pm.width() < width()-w2-x){
p.drawPixmap(x,maxExtent-pm.height()-1,
pm);
x += pm.width();
}
else {
p.drawPixmap(x,maxExtent-pm.height()-1,
pm,
0,0,width()-w2-x,pm.height());
break;
}
}
}
//bottom
pm = *framePixmaps[FrameBottom];
if (pm.width() > 0){
s = width()-w4-w3;
n = s/pm.width();
w = n>0?s/n:s;
m.reset();
m.scale(w/(float)pm.width(), 1);
pm = pm.transformed(m);
x = w3;
while (1){
if (pm.width() < width()-w4-x){
p.drawPixmap(x,height()-maxExtent+1,pm);
x += pm.width();
}
else {
p.drawPixmap(x,height()-maxExtent+1,pm,
0,0,width()-w4-x,pm.height());
break;
}
}
}
//left
pm = *framePixmaps[FrameLeft];
if (pm.height() > 0){
s = height()-h3-h1;
n = s/pm.height();
w = n>0?s/n:s;
m.reset();
m.scale(1, w/(float)pm.height());
pm = pm.transformed(m);
y = h1;
while (1){
if (pm.height() < height()-h3-y){
p.drawPixmap(maxExtent-pm.width()-1, y,
pm);
y += pm.height();
}
else {
p.drawPixmap(maxExtent-pm.width()-1, y,
pm,
0,0, pm.width(),
height()-h3-y);
break;
}
}
}
//right
pm = *framePixmaps[FrameRight];
if (pm.height() > 0){
s = height()-h4-h2;
n = s/pm.height();
w = n>0?s/n:s;
m.reset();
m.scale(1, w/(float)pm.height());
pm = pm.transformed(m);
y = h2;
while (1){
if (pm.height() < height()-h4-y){
p.drawPixmap(width()-maxExtent+1, y,
pm);
y += pm.height();
}
else {
p.drawPixmap(width()-maxExtent+1, y,
pm,
0,0, pm.width(),
height()-h4-y);
break;
}
}
}
drawTitle(p);
QColor c = widget()->colorGroup().background();
// KWM evidently had a 1 pixel border around the client window. We
// emulate it here, but should be removed at some point in order to
// seamlessly mesh widget themes
p.setPen(c);
p.drawRect(maxExtent-1, maxExtent-1, width()-(maxExtent-1)*2,
height()-(maxExtent-1)*2);
// We fill the area behind the wrapped widget to ensure that
// shading animation is drawn as smoothly as possible
QRect r(layout->cellGeometry(2, 1));
p.fillRect( r.x(), r.y(), r.width(), r.height(), c);
p.end();
}
void KWMThemeClient::doShape()
{
QBitmap shapemask(width(), height());
shapemask.fill(color0);
QPainter p;
p.begin(&shapemask);
p.setBrush(color1);
p.setPen(color1);
int x,y;
// first the corners
int w1 = framePixmaps[FrameTopLeft]->width();
int h1 = framePixmaps[FrameTopLeft]->height();
if (w1 > width()/2) w1 = width()/2;
if (h1 > height()/2) h1 = height()/2;
if (framePixmaps[FrameTopLeft]->mask())
p.drawPixmap(0,0,*framePixmaps[FrameTopLeft]->mask(),
0,0,w1, h1);
else
p.fillRect(0,0,w1,h1,color1);
int w2 = framePixmaps[FrameTopRight]->width();
int h2 = framePixmaps[FrameTopRight]->height();
if (w2 > width()/2) w2 = width()/2;
if (h2 > height()/2) h2 = height()/2;
if (framePixmaps[FrameTopRight]->mask())
p.drawPixmap(width()-w2,0,*framePixmaps[FrameTopRight]->mask(),
framePixmaps[FrameTopRight]->width()-w2,0,w2, h2);
else
p.fillRect(width()-w2,0,w2, h2,color1);
int w3 = framePixmaps[FrameBottomLeft]->width();
int h3 = framePixmaps[FrameBottomLeft]->height();
if (w3 > width()/2) w3 = width()/2;
if (h3 > height()/2) h3 = height()/2;
if (framePixmaps[FrameBottomLeft]->mask())
p.drawPixmap(0,height()-h3,*framePixmaps[FrameBottomLeft]->mask(),
0,framePixmaps[FrameBottomLeft]->height()-h3,w3, h3);
else
p.fillRect(0,height()-h3,w3,h3,color1);
int w4 = framePixmaps[FrameBottomRight]->width();
int h4 = framePixmaps[FrameBottomRight]->height();
if (w4 > width()/2) w4 = width()/2;
if (h4 > height()/2) h4 = height()/2;
if (framePixmaps[FrameBottomRight]->mask())
p.drawPixmap(width()-w4,height()-h4,*framePixmaps[FrameBottomRight]->mask(),
framePixmaps[FrameBottomRight]->width()-w4,
framePixmaps[FrameBottomRight]->height()-h4,
w4, h4);
else
p.fillRect(width()-w4,height()-h4,w4,h4,color1);
QPixmap pm;
QMatrix m;
int n,s,w;
//top
if (framePixmaps[FrameTop]->mask())
{
pm = *framePixmaps[FrameTop]->mask();
s = width()-w2-w1;
n = s/pm.width();
w = n>0?s/n:s;
m.reset();
m.scale(w/(float)pm.width(), 1);
pm = pm.transformed(m);
x = w1;
while (1){
if (pm.width() < width()-w2-x){
p.drawPixmap(x,maxExtent-pm.height()-1,
pm);
x += pm.width();
}
else {
p.drawPixmap(x,maxExtent-pm.height()-1,
pm,
0,0,width()-w2-x,pm.height());
break;
}
}
}
//bottom
if (framePixmaps[FrameBottom]->mask())
{
pm = *framePixmaps[FrameBottom]->mask();
s = width()-w4-w3;
n = s/pm.width();
w = n>0?s/n:s;
m.reset();
m.scale(w/(float)pm.width(), 1);
pm = pm.transformed(m);
x = w3;
while (1){
if (pm.width() < width()-w4-x){
p.drawPixmap(x,height()-maxExtent+1,pm);
x += pm.width();
}
else {
p.drawPixmap(x,height()-maxExtent+1,pm,
0,0,width()-w4-x,pm.height());
break;
}
}
}
//left
if (framePixmaps[FrameLeft]->mask())
{
pm = *framePixmaps[FrameLeft]->mask();
s = height()-h3-h1;
n = s/pm.height();
w = n>0?s/n:s;
m.reset();
m.scale(1, w/(float)pm.height());
pm = pm.transformed(m);
y = h1;
while (1){
if (pm.height() < height()-h3-y){
p.drawPixmap(maxExtent-pm.width()-1, y,
pm);
y += pm.height();
}
else {
p.drawPixmap(maxExtent-pm.width()-1, y,
pm,
0,0, pm.width(),
height()-h3-y);
break;
}
}
}
//right
if (framePixmaps[FrameRight]->mask())
{
pm = *framePixmaps[FrameRight]->mask();
s = height()-h4-h2;
n = s/pm.height();
w = n>0?s/n:s;
m.reset();
m.scale(1, w/(float)pm.height());
pm = pm.transformed(m);
y = h2;
while (1){
if (pm.height() < height()-h4-y){
p.drawPixmap(width()-maxExtent+1, y,
pm);
y += pm.height();
}
else {
p.drawPixmap(width()-maxExtent+1, y,
pm,
0,0, pm.width(),
height()-h4-y);
break;
}
}
}
p.fillRect(maxExtent-1, maxExtent-1, width()-2*maxExtent+2, height()-2*maxExtent+2, color1);
setMask(shapemask);
}
void KWMThemeClient::showEvent(QShowEvent *)
{
doShape();
widget()->repaint(false);
}
void KWMThemeClient::mouseDoubleClickEvent( QMouseEvent * e )
{
if (e->button() == LeftButton && titlebar->geometry().contains( e->pos() ) )
titlebarDblClickOperation();
}
void KWMThemeClient::desktopChange()
{
if (stickyBtn) {
bool on = isOnAllDesktops();
stickyBtn->setPixmap(on ? *pindownPix : *pinupPix);
stickyBtn->setToolTip( on ? i18n("Unsticky") : i18n("Sticky") );
}
}
void KWMThemeClient::maximizeChange()
{
if (maxBtn) {
bool m = maximizeMode() == MaximizeFull;
maxBtn->setPixmap(m ? *minmaxPix : *maxPix);
maxBtn->setToolTip( m ? i18n("Restore") : i18n("Maximize"));
}
}
void KWMThemeClient::slotMaximize()
{
maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull );
}
void KWMThemeClient::activeChange()
{
widget()->update();
}
KDecoration::Position KWMThemeClient::mousePosition(const QPoint &p) const
{
Position m = KDecoration::mousePosition(p);
// corners
if(p.y() < framePixmaps[FrameTop]->height() &&
p.x() < framePixmaps[FrameLeft]->width()){
m = PositionTopLeft;
}
else if(p.y() < framePixmaps[FrameTop]->height() &&
p.x() > width()-framePixmaps[FrameRight]->width()){
m = PositionTopRight;
}
else if(p.y() > height()-framePixmaps[FrameBottom]->height() &&
p.x() < framePixmaps[FrameLeft]->width()){
m = PositionBottomLeft;
}
else if(p.y() > height()-framePixmaps[FrameBottom]->height() &&
p.x() > width()-framePixmaps[FrameRight]->width()){
m = PositionBottomRight;
} // edges
else if(p.y() < framePixmaps[FrameTop]->height())
m = PositionTop;
else if(p.y() > height()-framePixmaps[FrameBottom]->height())
m = PositionBottom;
else if(p.x() < framePixmaps[FrameLeft]->width())
m = PositionLeft;
else if(p.x() > width()-framePixmaps[FrameRight]->width())
m = PositionRight;
return(m);
}
void KWMThemeClient::menuButtonPressed()
{
mnuBtn->setDown(false); // will stay down if I don't do this
QPoint pos = mnuBtn->mapToGlobal(mnuBtn->rect().bottomLeft());
showWindowMenu( pos );
}
void KWMThemeClient::iconChange()
{
if(mnuBtn){
if( icon().pixmap( QIcon::Small, QIcon::Normal ).isNull()){
mnuBtn->setPixmap(*menuPix);
}
else{
mnuBtn->setPixmap(icon().pixmap( QIcon::Small, QIcon::Normal ));
}
}
}
bool KWMThemeClient::eventFilter( QObject* o, QEvent* e )
{
if ( o != widget() )
return false;
switch ( e->type() )
{
case QEvent::Resize:
resizeEvent( static_cast< QResizeEvent* >( e ) );
return true;
case QEvent::Paint:
paintEvent( static_cast< QPaintEvent* >( e ) );
return true;
case QEvent::MouseButtonDblClick:
mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) );
return true;
case QEvent::MouseButtonPress:
processMousePressEvent( static_cast< QMouseEvent* >( e ) );
return true;
case QEvent::Show:
showEvent( static_cast< QShowEvent* >( e ) );
return true;
default:
return false;
}
}
QSize KWMThemeClient::minimumSize() const
{
return widget()->minimumSize().expandedTo( QSize( 100, 50 ));
}
void KWMThemeClient::resize( const QSize& s )
{
widget()->resize( s );
}
void KWMThemeClient::borders( int& left, int& right, int& top, int& bottom ) const
{
left =
right =
top =
bottom =
TODO
}
KWMThemeFactory::KWMThemeFactory()
{
create_pixmaps();
}
KWMThemeFactory::~KWMThemeFactory()
{
delete_pixmaps();
}
KDecoration* KWMThemeFactory::createDecoration( KDecorationBridge* b )
{
return new KWMThemeClient( b, this );
}
bool KWMThemeFactory::reset( unsigned long mask )
{
bool needHardReset = false;
TODO
// doesn't obey the Border size setting
if( mask & ( SettingFont | SettingButtons ))
needHardReset = true;
if( mask & ( SettingFont | SettingColors )) {
KWMTheme::delete_pixmaps();
KWMTheme::create_pixmaps();
}
if( !needHardReset )
resetDecorations( mask );
return needHardReset;
}
}
extern "C"
{
KDE_EXPORT KDecorationFactory *create_factory()
{
return new KWMTheme::KWMThemeFactory();
}
}
#include "kwmthemeclient.moc"

View file

@ -0,0 +1,74 @@
#ifndef __KWMTHEMECLIENT_H
#define __KWMTHEMECLIENT_H
#include <qbutton.h>
#include <QToolButton>
#include <QPixmap>
#include <kdecoration.h>
#include <kdecorationfactory.h>
class QLabel;
class QSpacerItem;
class QGridLayout;
namespace KWMTheme {
class MyButton : public QToolButton
{
public:
MyButton(QWidget *parent=0, const char *name=0)
: QToolButton(parent, name){setAutoRaise(true);setCursor( arrowCursor ); }
protected:
void drawButtonLabel(QPainter *p);
};
class KWMThemeClient : public KDecoration
{
Q_OBJECT
public:
KWMThemeClient( KDecorationBridge* b, KDecorationFactory* f );
~KWMThemeClient(){;}
void init();
void resize( const QSize& s );
QSize minimumSize() const;
void borders( int& left, int& right, int& top, int& bottom ) const;
protected:
void doShape();
void drawTitle(QPainter &p);
void resizeEvent( QResizeEvent* );
void paintEvent( QPaintEvent* );
void showEvent( QShowEvent* );
void mouseDoubleClickEvent( QMouseEvent * );
bool eventFilter( QObject* o, QEvent* e );
void captionChange();
void desktopChange();
void maximizeChange();
void iconChange();
void activeChange();
void shadeChange() {};
Position mousePosition(const QPoint &) const;
protected slots:
//void slotReset();
void menuButtonPressed();
void slotMaximize();
private:
QPixmap buffer;
KPixmap *aGradient, *iGradient;
MyButton *maxBtn, *stickyBtn, *mnuBtn;
QSpacerItem *titlebar;
QGridLayout* layout;
};
class KWMThemeFactory : public KDecorationFactory
{
public:
KWMThemeFactory();
~KWMThemeFactory();
KDecoration* createDecoration( KDecorationBridge* b );
bool reset( unsigned long mask );
};
}
#endif

View file

@ -0,0 +1,23 @@
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin3_laptop_PART_SRCS laptopclient.cpp )
kde4_automoc(kwin3_laptop ${kwin3_laptop_PART_SRCS})
kde4_add_plugin(kwin3_laptop ${kwin3_laptop_PART_SRCS})
target_link_libraries(kwin3_laptop ${KDE4_KDECORE_LIBS} kdecorations kdefx )
install(TARGETS kwin3_laptop DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES laptop.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin )

View file

@ -0,0 +1,6 @@
[Desktop Entry]
Encoding=UTF-8
Name=Laptop
Name[fr]=Ordinateur portable
Name[x-test]=xxLaptopxx
X-KDE-Library=kwin3_laptop

View file

@ -0,0 +1,771 @@
/*
* Laptop KWin Decoration
*
* Copyright (c) 2005 Sandro Giessl <sandro@giessl.com>
* Port of this decoration to KDE 3.2, accessibility enhancement are
* Copyright (c) 2003 Luciano Montanaro <mikelima@cirulla.net>
*/
#include <kconfig.h> // up here to avoid X11 header conflict :P
#include "laptopclient.h"
#include <qdrawutil.h>
//Added by qt3to4:
#include <QPixmap>
#include <QPaintEvent>
#include <kpixmapeffect.h>
#include <QPixmap>
#include <kdrawutil.h>
#include <kglobal.h>
#include <klocale.h>
#include <QBitmap>
namespace Laptop {
static const unsigned char iconify_bits[] = {
0xff, 0xff, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18};
static const unsigned char close_bits[] = {
0x42, 0xe7, 0x7e, 0x3c, 0x3c, 0x7e, 0xe7, 0x42};
static const unsigned char maximize_bits[] = {
0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0xff, 0xff };
static const unsigned char r_minmax_bits[] = {
0x0c, 0x18, 0x33, 0x67, 0xcf, 0x9f, 0x3f, 0x3f};
static const unsigned char l_minmax_bits[] = {
0x30, 0x18, 0xcc, 0xe6, 0xf3, 0xf9, 0xfc, 0xfc};
static const unsigned char question_bits[] = {
0x3c, 0x66, 0x60, 0x30, 0x18, 0x00, 0x18, 0x18};
static const unsigned char unsticky_bits[] = {
0x3c, 0x42, 0x99, 0xbd, 0xbd, 0x99, 0x42, 0x3c};
static const unsigned char sticky_bits[] = {
0x3c, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3c};
static QPixmap *titlePix;
static QPixmap *aUpperGradient;
static QPixmap *iUpperGradient;
// buttons active, inactive, up, down, and 2 sizes :P
static QPixmap *btnPix1;
static QPixmap *iBtnPix1;
static QPixmap *btnDownPix1;
static QPixmap *iBtnDownPix1;
static QPixmap *btnPix2;
static QPixmap *btnDownPix2;
static QPixmap *iBtnPix2;
static QPixmap *iBtnDownPix2;
static QColor btnForeground;
static int titleHeight = 14;
static int btnWidth1 = 17;
static int btnWidth2 = 27;
static int handleSize = 8; // the resize handle size in pixels
static bool pixmaps_created = false;
// =====================================
extern "C" KDE_EXPORT KDecorationFactory* create_factory()
{
return new Laptop::LaptopClientFactory();
}
// =====================================
static inline const KDecorationOptions* options()
{
return KDecoration::options();
}
static void drawButtonFrame(QPixmap *pix, const QPalette &g, bool sunken)
{
QPainter p;
int w = pix->width();
int h = pix->height();
int x2 = w-1;
int y2 = h-1;
p.begin(pix);
if(sunken){
qDrawShadePanel(&p, 0, 0, w, h, g, true, 2);
}
else{
p.setPen(g.color(QPalette::Dark ));
p.drawRect(0, 0, w-1, h-1);
p.setPen(g.color(QPalette::Light));
p.drawLine(x2, 0, x2, y2);
p.drawLine(0, y2, x2, y2);
p.drawLine(1, 1, x2-2, 1);
p.drawLine(1, 1, 1, y2-2);
p.end();
}
}
static void create_pixmaps()
{
if(pixmaps_created)
return;
pixmaps_created = true;
titleHeight = QFontMetrics(options()->font(true)).height() + 2;
if (titleHeight < handleSize) titleHeight = handleSize;
titleHeight &= ~1; // Make title height even
if (titleHeight < 14) titleHeight = 14;
btnWidth1 = titleHeight + 3;
btnWidth2 = 3*titleHeight/2 + 6;
// titlebar
QPainter p;
QPainter maskPainter;
int i, x, y;
titlePix = new QPixmap(33, 12);
QBitmap mask(33, 12);
mask.fill(Qt::color0);
p.begin(titlePix);
maskPainter.begin(&mask);
maskPainter.setPen(Qt::color1);
for(i=0, y=2; i < 3; ++i, y+=4){
for(x=1; x <= 33; x+=3){
p.setPen(options()->color(KDecoration::ColorTitleBar, true).light(150));
p.drawPoint(x, y);
maskPainter.drawPoint(x, y);
p.setPen(options()->color(KDecoration::ColorTitleBar, true).dark(150));
p.drawPoint(x+1, y+1);
maskPainter.drawPoint(x+1, y+1);
}
}
p.end();
maskPainter.end();
titlePix->setMask(mask);
if(QPixmap::defaultDepth() > 8){
aUpperGradient = new QPixmap(32, titleHeight+2);
iUpperGradient = new QPixmap(32, titleHeight+2);
QColor bgColor = options()->color(KDecoration::ColorTitleBar, true);
KPixmapEffect::gradient(*aUpperGradient,
bgColor.light(120),
bgColor.dark(120),
KPixmapEffect::VerticalGradient);
bgColor = options()->color(KDecoration::ColorTitleBar, false);
KPixmapEffect::gradient(*iUpperGradient,
bgColor.light(120),
bgColor.dark(120),
KPixmapEffect::VerticalGradient);
}
// buttons (active/inactive, sunken/unsunken, 2 sizes each)
QPalette g = options()->palette(KDecoration::ColorButtonBg, true);
g.setCurrentColorGroup( QPalette::Active );
QColor c = g.color( QPalette::Background );
btnPix1 = new QPixmap(btnWidth1, titleHeight);
btnDownPix1 = new QPixmap(btnWidth1, titleHeight);
btnPix2 = new QPixmap(btnWidth2, titleHeight);
btnDownPix2 = new QPixmap(btnWidth2, titleHeight);
iBtnPix1 = new QPixmap(btnWidth1, titleHeight);
iBtnDownPix1 = new QPixmap(btnWidth1, titleHeight);
iBtnPix2 = new QPixmap(btnWidth2, titleHeight);
iBtnDownPix2 = new QPixmap(btnWidth2, titleHeight);
if(QPixmap::defaultDepth() > 8){
KPixmapEffect::gradient(*btnPix1, c.light(120), c.dark(130),
KPixmapEffect::DiagonalGradient);
KPixmapEffect::gradient(*btnDownPix1, c.dark(130), c.light(120),
KPixmapEffect::DiagonalGradient);
KPixmapEffect::gradient(*btnPix2, c.light(120), c.dark(130),
KPixmapEffect::DiagonalGradient);
KPixmapEffect::gradient(*btnDownPix2, c.dark(130), c.light(120),
KPixmapEffect::DiagonalGradient);
g = options()->palette(KDecoration::ColorButtonBg, false);
g.setCurrentColorGroup( QPalette::Active );
c = g.color(QPalette::Background);
KPixmapEffect::gradient(*iBtnPix1, c.light(120), c.dark(130),
KPixmapEffect::DiagonalGradient);
KPixmapEffect::gradient(*iBtnDownPix1, c.dark(130), c.light(120),
KPixmapEffect::DiagonalGradient);
KPixmapEffect::gradient(*iBtnPix2, c.light(120), c.dark(130),
KPixmapEffect::DiagonalGradient);
KPixmapEffect::gradient(*iBtnDownPix2, c.dark(130), c.light(120),
KPixmapEffect::DiagonalGradient);
}
else{
btnPix1->fill(c.rgb());
btnDownPix1->fill(c.rgb());
btnPix2->fill(c.rgb());
btnDownPix2->fill(c.rgb());
g = options()->palette(KDecoration::ColorButtonBg, false);
g.setCurrentColorGroup( QPalette::Active );
c = g.background().color();
iBtnPix1->fill(c.rgb());
iBtnDownPix1->fill(c.rgb());
iBtnPix2->fill(c.rgb());
iBtnDownPix2->fill(c.rgb());
}
g = options()->palette(KDecoration::ColorButtonBg, true);
g.setCurrentColorGroup( QPalette::Active );
c = g.background().color();
drawButtonFrame(btnPix1, g, false);
drawButtonFrame(btnDownPix1, g, true);
drawButtonFrame(btnPix2, g, false);
drawButtonFrame(btnDownPix2, g, true);
g = options()->palette(KDecoration::ColorButtonBg, false);
g.setCurrentColorGroup( QPalette::Active );
c = g.background().color();
drawButtonFrame(iBtnPix1, g, false);
drawButtonFrame(iBtnDownPix1, g, true);
drawButtonFrame(iBtnPix2, g, false);
drawButtonFrame(iBtnDownPix2, g, true);
if(qGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 128)
btnForeground = Qt::black;
else
btnForeground = Qt::white;
}
static void delete_pixmaps()
{
delete titlePix;
if(aUpperGradient){
delete aUpperGradient;
delete iUpperGradient;
delete btnPix1;
delete btnDownPix1;
delete iBtnPix1;
delete iBtnDownPix1;
delete btnPix2;
delete btnDownPix2;
delete iBtnPix2;
delete iBtnDownPix2;
}
pixmaps_created = false;
}
// =====================================
LaptopButton::LaptopButton(ButtonType type, LaptopClient *parent, const char *name)
: KCommonDecorationButton(type, parent)
{
setAttribute(Qt::WA_NoSystemBackground, true);
}
void LaptopButton::reset(unsigned long changed)
{
if (changed&DecorationReset || changed&ManualReset || changed&SizeChange || changed&StateChange) {
switch (type() ) {
case CloseButton:
setBitmap(close_bits);
break;
case HelpButton:
setBitmap(question_bits);
break;
case MinButton:
setBitmap(iconify_bits);
break;
case MaxButton:
if (isChecked() ) {
setBitmap(isLeft() ? l_minmax_bits : r_minmax_bits);
} else {
setBitmap(maximize_bits);
}
break;
case OnAllDesktopsButton:
setBitmap( isChecked() ? unsticky_bits : sticky_bits );
break;
default:
setBitmap(0);
break;
}
this->update();
}
}
void LaptopButton::setBitmap(const unsigned char *bitmap)
{
if (bitmap)
deco = QBitmap(8, 8, bitmap, true);
else {
deco = QBitmap(8,8);
deco.fill(Qt::color0);
}
deco.setMask(deco);
repaint();
}
void LaptopButton::paintEvent(QPaintEvent *)
{
QPainter p(this);
drawButton(&p);
}
void LaptopButton::drawButton(QPainter *p)
{
bool smallBtn = width() == btnWidth1;
if(btnPix1){
if(decoration()->isActive()){
if(isDown())
p->drawPixmap(0, 0, smallBtn ? *btnDownPix1 : *btnDownPix2);
else
p->drawPixmap(0, 0, smallBtn ? *btnPix1 : *btnPix2);
}
else{
if(isDown())
p->drawPixmap(0, 0, smallBtn ? *iBtnDownPix1 : *iBtnDownPix2);
else
p->drawPixmap(0, 0, smallBtn ? *iBtnPix1 : *iBtnPix2);
}
}
else{
QPalette g = options()->palette(KDecoration::ColorButtonBg, decoration()->isActive());
g.setCurrentColorGroup( QPalette::Active );
int w = width();
int h = height();
p->fillRect(1, 1, w-2, h-2, isDown() ? g.color(QPalette::Mid) : g.color(QPalette::Button) );
p->setPen(isDown() ? g.color( QPalette::Dark ) : g.color( QPalette::Light ));
p->drawLine(0, 0, w-1, 0);
p->drawLine(0, 0, 0, w-1);
p->setPen(isDown() ? g.color( QPalette::Light ) : g.color( QPalette::Dark ));
p->drawLine(w-1, 0, w-1, h-1);
p->drawLine(0, h-1, w-1, h-1);
}
p->setPen(btnForeground);
int xOff = (width()-8)/2;
int yOff = (height()-8)/2;
p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, deco);
}
// =====================================
void LaptopClient::reset(unsigned long changed)
{
KCommonDecoration::reset(changed);
}
LaptopClient::LaptopClient(KDecorationBridge *b, KDecorationFactory *f)
: KCommonDecoration(b, f)
{
}
LaptopClient::~LaptopClient()
{
}
QString LaptopClient::visibleName() const
{
return i18n("Laptop");
}
QString LaptopClient::defaultButtonsLeft() const
{
return "X";
}
QString LaptopClient::defaultButtonsRight() const
{
return "HSIA";
}
bool LaptopClient::decorationBehaviour(DecorationBehaviour behaviour) const
{
switch (behaviour) {
case DB_MenuClose:
return false;
case DB_WindowMask:
return true;
case DB_ButtonHide:
return true;
default:
return KCommonDecoration::decorationBehaviour(behaviour);
}
}
int LaptopClient::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const
{
switch (lm) {
case LM_TitleEdgeLeft:
case LM_TitleEdgeRight:
case LM_BorderLeft:
case LM_BorderRight:
return 4;
case LM_BorderBottom:
return mustDrawHandle() ? handleSize : 4;
case LM_TitleEdgeTop:
return 3;
case LM_TitleEdgeBottom:
return 1;
case LM_TitleBorderLeft:
case LM_TitleBorderRight:
return 0;
case LM_ButtonWidth:
{
if (btn && (btn->type()==HelpButton||btn->type()==OnAllDesktopsButton) ) {
return btnWidth1;
} else {
return btnWidth2;
}
}
case LM_ButtonHeight:
case LM_TitleHeight:
if (isToolWindow() )
return titleHeight-2;
else
return titleHeight;
case LM_ButtonSpacing:
return 0;
case LM_ExplicitButtonSpacer:
return 0;
default:
return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
}
}
KCommonDecorationButton *LaptopClient::createButton(ButtonType type)
{
switch (type) {
case OnAllDesktopsButton:
return new LaptopButton(OnAllDesktopsButton, this, "on_all_desktops");
case HelpButton:
return new LaptopButton(HelpButton, this, "help");
case MinButton:
return new LaptopButton(MinButton, this, "minimize");
case MaxButton:
return new LaptopButton(MaxButton, this, "maximize");
case CloseButton:
return new LaptopButton(CloseButton, this, "close");
default:
return 0;
}
}
void LaptopClient::init()
{
bufferDirty = true;
KCommonDecoration::init();
}
void LaptopClient::captionChange()
{
bufferDirty = true;
KCommonDecoration::captionChange();
}
void LaptopClient::paintEvent( QPaintEvent* )
{
QPainter p(widget());
QPalette g = options()->palette(KDecoration::ColorFrame, isActive());
g.setCurrentColorGroup( QPalette::Active );
QRect r(widget()->rect());
p.setPen(Qt::black);
p.drawRect(r);
// fill mid frame...
p.setPen(g.background().color());
p.drawLine(r.x()+2, r.y()+2, r.right()-2, r.y()+2);
p.drawLine(r.left()+2, r.y()+3, r.left()+2, r.bottom()-layoutMetric(LM_BorderBottom)+1 );
p.drawLine(r.right()-2, r.y()+3, r.right()-2, r.bottom()-layoutMetric(LM_BorderBottom)+1 );
p.drawLine(r.left()+3, r.y()+3, r.left()+3, r.y()+layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeTop) );
p.drawLine(r.right()-3, r.y()+3, r.right()-3, r.y()+layoutMetric(LM_TitleEdgeTop)+layoutMetric(LM_TitleHeight)+layoutMetric(LM_TitleEdgeTop) );
if (!mustDrawHandle() )
p.drawLine(r.left()+1, r.bottom()-2, r.right()-1, r.bottom()-2);
// outer frame
p.setPen(g.color(QPalette::Light));
p.drawLine(r.x()+1, r.y()+1, r.right()-1, r.y()+1);
p.drawLine(r.x()+1, r.y()+1, r.x()+1, r.bottom()-1);
p.setPen(g.dark().color());
p.drawLine(r.right()-1, r.y()+1, r.right()-1, r.bottom()-1);
p.drawLine(r.x()+1, r.bottom()-1, r.right()-1, r.bottom()-1);
int th = titleHeight;
int bb = handleSize + 2; // Bottom border
int bs = handleSize - 2; // inner size of bottom border
if (!mustDrawHandle()) {
bb = 6;
bs = 0;
}
if ( isToolWindow() )
th -= 2;
// inner rect
p.drawRect(r.x() + 3, r.y() + th + 3, r.width() - 6, r.height() - th - bb);
// handles
if (mustDrawHandle()) {
if (r.width() > 3*handleSize + 20) {
int range = 8 + 3*handleSize/2;
qDrawShadePanel(&p, r.x() + 1, r.bottom() - bs, range,
handleSize - 2, g, false, 1, &g.brush(QPalette::Mid));
qDrawShadePanel(&p, r.x() + range + 1, r.bottom() - bs,
r.width() - 2*range - 2, handleSize - 2, g, false, 1,
isActive() ? &g.brush(QPalette::Background) :
&g.brush(QPalette::Mid));
qDrawShadePanel(&p, r.right() - range, r.bottom() - bs,
range, bs, g, false, 1, &g.brush(QPalette::Mid));
} else {
qDrawShadePanel(&p, r.x() + 1, r.bottom() - bs,
r.width() - 2, bs, g, false, 1,
isActive() ? &g.brush(QPalette::Background) :
&g.brush(QPalette::Mid));
}
}
r = titleRect();
if(isActive()){
updateActiveBuffer();
p.drawPixmap(r.x(), r.y(), activeBuffer);
p.setPen(g.background().color());
p.drawPoint(r.x(), r.y());
p.drawPoint(r.right(), r.y());
p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
}
else{
if(iUpperGradient)
p.drawTiledPixmap(r.x(), r.y(), r.width(), r.height()-1,
*iUpperGradient);
else
p.fillRect(r.x(), r.y(), r.width(), r.height()-1,
options()->color(KDecoration::ColorTitleBar, false));
p.setFont(options()->font(false, isToolWindow() ));
QFontMetrics fm(options()->font(false));
g = options()->palette(KDecoration::ColorTitleBar, false);
g.setCurrentColorGroup( QPalette::Active );
if(iUpperGradient)
p.drawTiledPixmap(r.x()+((r.width()-fm.width(caption()))/2)-4,
r.y(), fm.width(caption())+8, r.height()-1,
*iUpperGradient);
else
p.fillRect(r.x()+((r.width()-fm.width(caption()))/2)-4, r.y(),
fm.width(caption())+8, r.height()-1,
g.brush(QPalette::Background));
p.setPen(g.mid().color());
p.drawLine(r.x(), r.y(), r.right(), r.y());
p.drawLine(r.x(), r.y(), r.x(), r.bottom());
p.setPen(g.color(QPalette::Button));
p.drawLine(r.right(), r.y(), r.right(), r.bottom());
p.drawLine(r.x(), r.bottom(), r.right(), r.bottom());
p.setPen(options()->color(KDecoration::ColorFont, false));
p.drawText(r.x(), r.y(), r.width(), r.height()-1,
Qt::AlignCenter, caption() );
g = options()->palette(KDecoration::ColorFrame, true);
g.setCurrentColorGroup( QPalette::Active );
p.setPen(g.background().color());
p.drawPoint(r.x(), r.y());
p.drawPoint(r.right(), r.y());
p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
}
}
QRegion LaptopClient::cornerShape(WindowCorner corner)
{
switch (corner) {
case WC_TopLeft:
return QRect(0, 0, 1, 1);
case WC_TopRight:
return QRect(width()-1, 0, 1, 1);
case WC_BottomLeft:
return QRect(0, height()-1, 1, 1);
case WC_BottomRight:
return QRect(width()-1, height()-1, 1, 1);
default:
return QRegion();
}
}
bool LaptopClient::mustDrawHandle() const
{
bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
return false;
} else {
return isResizable();
}
}
void LaptopClient::updateActiveBuffer( )
{
QRect rTitle = titleRect();
if( !bufferDirty && (lastBufferWidth == rTitle.width()))
return;
if ( rTitle.width() <= 0 || rTitle.height() <= 0 )
return;
lastBufferWidth = rTitle.width();
bufferDirty = false;
activeBuffer = QPixmap(rTitle.width(), rTitle.height());
QPainter p;
QRect r(0, 0, activeBuffer.width(), activeBuffer.height());
p.begin(&activeBuffer);
if(aUpperGradient){
p.drawTiledPixmap(r, *aUpperGradient);
}
else{
p.fillRect(r, options()->color(KDecoration::ColorTitleBar, true));
}
if(titlePix)
p.drawTiledPixmap(r, *titlePix);
p.setFont(options()->font(true, isToolWindow() ));
QFontMetrics fm(options()->font(true));
QPalette g = options()->palette(KDecoration::ColorTitleBar, true);
g.setCurrentColorGroup( QPalette::Active );
if(aUpperGradient)
p.drawTiledPixmap(r.x()+((r.width()-fm.width(caption()))/2)-4,
r.y(), fm.width(caption())+8, r.height()-1,
*aUpperGradient);
else
p.fillRect(r.x()+((r.width()-fm.width(caption()))/2)-4, 0,
fm.width(caption())+8, r.height(),
g.brush(QPalette::Background));
p.setPen(g.mid().color());
p.drawLine(r.x(), r.y(), r.right(), r.y());
p.drawLine(r.x(), r.y(), r.x(), r.bottom());
p.setPen(g.color(QPalette::Button));
p.drawLine(r.right(), r.y(), r.right(), r.bottom());
p.drawLine(r.x(), r.bottom(), r.right(), r.bottom());
p.setPen(options()->color(KDecoration::ColorFont, true));
p.drawText(r.x(), r.y(), r.width(), r.height()-1,
Qt::AlignCenter, caption() );
g = options()->palette(KDecoration::ColorFrame, true);
g.setCurrentColorGroup( QPalette::Active );
p.setPen(g.background().color());
p.drawPoint(r.x(), r.y());
p.drawPoint(r.right(), r.y());
p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
p.end();
}
static const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask |
NET::DesktopMask | NET::DockMask | NET::ToolbarMask | NET::MenuMask |
NET::DialogMask | /*NET::OverrideMask |*/ NET::TopMenuMask |
NET::UtilityMask | NET::SplashMask;
bool LaptopClient::isTransient() const
{
NET::WindowType type = windowType(SUPPORTED_WINDOW_TYPES_MASK);
return type == NET::Dialog;
}
// =====================================
LaptopClientFactory::LaptopClientFactory()
{
create_pixmaps();
}
LaptopClientFactory::~LaptopClientFactory()
{
delete_pixmaps();
}
KDecoration *LaptopClientFactory::createDecoration(KDecorationBridge *b)
{
findPreferredHandleSize();
return new Laptop::LaptopClient(b, this);
}
bool LaptopClientFactory::reset(unsigned long changed)
{
findPreferredHandleSize();
// TODO Do not recreate decorations if it is not needed. Look at
// ModernSystem for how to do that
Laptop::delete_pixmaps();
Laptop::create_pixmaps();
bool needHardReset = true;
if (changed & SettingButtons) {
// handled by KCommonDecoration
needHardReset = false;
}
if (needHardReset) {
return true;
} else {
resetDecorations(changed);
return false;
}
}
bool LaptopClientFactory::supports( Ability ability )
{
switch( ability )
{
case AbilityAnnounceButtons:
case AbilityButtonOnAllDesktops:
case AbilityButtonHelp:
case AbilityButtonMinimize:
case AbilityButtonMaximize:
case AbilityButtonClose:
return true;
default:
return false;
};
}
QList< LaptopClientFactory::BorderSize >
LaptopClientFactory::borderSizes() const
{
// the list must be sorted
return QList< BorderSize >() << BorderNormal << BorderLarge <<
BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
}
void LaptopClientFactory::findPreferredHandleSize()
{
switch (options()->preferredBorderSize(this)) {
case KDecoration::BorderLarge:
handleSize = 11;
break;
case KDecoration::BorderVeryLarge:
handleSize = 16;
break;
case KDecoration::BorderHuge:
handleSize = 24;
break;
case KDecoration::BorderVeryHuge:
handleSize = 32;
break;
case KDecoration::BorderOversized:
handleSize = 40;
break;
case KDecoration::BorderTiny:
case KDecoration::BorderNormal:
default:
handleSize = 8;
}
}
} // Laptop namespace
// vim: sw=4

View file

@ -0,0 +1,77 @@
/*
* Laptop KWin Client
*
* Copyright (c) 2005 Sandro Giessl <sandro@giessl.com>
* Ported to the kde3.2 API by Luciano Montanaro <mikelima@cirulla.net>
*/
#ifndef __KDECLIENT_H
#define __KDECLIENT_H
#include <QBitmap>
#include <QPixmap>
#include <kcommondecoration.h>
#include <kdecorationfactory.h>
namespace Laptop {
class LaptopClient;
class LaptopButton : public KCommonDecorationButton
{
public:
LaptopButton(ButtonType type, LaptopClient *parent, const char *name);
void setBitmap(const unsigned char *bitmap);
virtual void reset(unsigned long changed);
protected:
void paintEvent(QPaintEvent *);
virtual void drawButton(QPainter *p);
QBitmap deco;
};
class LaptopClient : public KCommonDecoration
{
public:
LaptopClient( KDecorationBridge* b, KDecorationFactory* f );
~LaptopClient();
virtual QString visibleName() const;
virtual QString defaultButtonsLeft() const;
virtual QString defaultButtonsRight() const;
virtual bool decorationBehaviour(DecorationBehaviour behaviour) const;
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
virtual KCommonDecorationButton *createButton(ButtonType type);
virtual QRegion cornerShape(WindowCorner corner);
void init();
protected:
void paintEvent( QPaintEvent* );
void reset( unsigned long );
void updateActiveBuffer();
void captionChange();
private:
bool mustDrawHandle() const;
bool isTransient() const;
private:
QPixmap activeBuffer;
int lastBufferWidth;
bool bufferDirty;
};
class LaptopClientFactory : public QObject, public KDecorationFactory
{
public:
LaptopClientFactory();
virtual ~LaptopClientFactory();
virtual KDecoration* createDecoration( KDecorationBridge* );
virtual bool reset( unsigned long changed );
virtual bool supports( Ability ability );
virtual QList< BorderSize > borderSizes() const;
private:
void findPreferredHandleSize();
};
}
#endif

View file

@ -0,0 +1,25 @@
add_subdirectory( config )
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin3_modernsys_PART_SRCS modernsys.cpp )
kde4_automoc(kwin3_modernsys ${kwin3_modernsys_PART_SRCS})
kde4_add_plugin(kwin3_modernsys ${kwin3_modernsys_PART_SRCS})
target_link_libraries(kwin3_modernsys ${KDE4_KDECORE_LIBS} kdecorations kdefx ${QT_QTGUI_LIBRARY})
install(TARGETS kwin3_modernsys DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES modernsystem.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin/ )

View file

@ -0,0 +1,93 @@
/* XPM */
static const char * btnhighcolor_xpm[] = {
"14 15 75 1",
" c None",
". c #6E6E6E",
"+ c #757575",
"@ c #878787",
"# c #7D7D7D",
"$ c #9E9E9E",
"% c #B9B9B9",
"& c #C6C6C6",
"* c #BABABA",
"= c #A5A5A5",
"- c #7F7F7F",
"; c #848484",
"> c #A7A7A7",
", c #BFBFBF",
"' c #D1D1D1",
") c #D7D7D7",
"! c #DADADA",
"~ c #CBCBCB",
"{ c #ABABAB",
"] c #B3B3B3",
"^ c #C2C2C2",
"/ c #CACACA",
"( c #C9C9C9",
"_ c #B6B6B6",
": c #9A9A9A",
"< c #999999",
"[ c #B0B0B0",
"} c #C4C4C4",
"| c #C3C3C3",
"1 c #C0C0C0",
"2 c #AEAEAE",
"3 c #969696",
"4 c #C1C1C1",
"5 c #CCCCCC",
"6 c #C5C5C5",
"7 c #BEBEBE",
"8 c #AAAAAA",
"9 c #CECECE",
"0 c #D4D4D4",
"a c #DBDBDB",
"b c #DEDEDE",
"c c #D5D5D5",
"d c #D3D3D3",
"e c #BCBCBC",
"f c #CDCDCD",
"g c #E0E0E0",
"h c #E4E4E4",
"i c #E8E8E8",
"j c #EBEBEB",
"k c #E9E9E9",
"l c #E6E6E6",
"m c #DDDDDD",
"n c #E1E1E1",
"o c #EDEDED",
"p c #F1F1F1",
"q c #F5F5F5",
"r c #F8F8F8",
"s c #F6F6F6",
"t c #F3F3F3",
"u c #EEEEEE",
"v c #E5E5E5",
"w c #DCDCDC",
"x c #B7B7B7",
"y c #E2E2E2",
"z c #FDFDFD",
"A c #FFFFFF",
"B c #FCFCFC",
"C c #F7F7F7",
"D c #B5B5B5",
"E c #F2F2F2",
"F c #FAFAFA",
"G c #9B9B9B",
"H c #FBFBFB",
"I c #A9A9A9",
"J c #747474",
" .... ",
" ..+@@+.. ",
" .#$%&&*=-. ",
" .;>,')!)~{#. ",
" .$]^///(&_:. ",
".<[*^}||11*23.",
".[4&5555~(678.",
".,90!aba)cd~e.",
".faghijklhm06.",
".'nopqrstuvw/.",
".xyprzAzBCunD.",
" .'EzAAAAFpf. ",
" .GcHAAAAF0<. ",
" ..I5kk5I.. ",
" J..... "};

View file

@ -0,0 +1,42 @@
/* Image bits processed by KPixmap2Bitmaps */
#define lowcolor_mask_width 14
#define lowcolor_mask_height 15
static const unsigned char lowcolor_mask_bits[] = {
0xf0,0x03,0xf8,0x07,0xfc,0xcf,0xfe,0x1f,0xfe,0x1f,0xff,0xff,0xff,0xff,0xff,
0x3f,0xff,0x3f,0xff,0xbf,0xfe,0xdf,0xfe,0x9f,0xfc,0x0f,0xf8,0x07,0xf0,0x03,
0x00,0x40,0x80,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x7c,0xfe,0x87,0x40,0x00,
0x00,0x64,0x00,0x20,0x00,0x64,0x00,0x86,0xfe,0x87,0x40,0x00,0x00,0x65,0x00 };
#define lowcolor_6a696a_width 14
#define lowcolor_6a696a_height 15
static const unsigned char lowcolor_6a696a_bits[] = {
0xf0,0x03,0x18,0x06,0x04,0xcc,0x06,0x18,0x02,0x10,0x00,0xc0,0x00,0xc0,0x00,
0x00,0x00,0x00,0x00,0xc0,0x00,0xc0,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x40,0x80,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,
0x00,0x00,0x00,0x80,0x24,0x0e,0x08,0x61,0x00,0x00,0x00,0xf0,0xd9,0x0c,0x08 };
#define lowcolor_949194_width 14
#define lowcolor_949194_height 15
static const unsigned char lowcolor_949194_bits[] = {
0x00,0x40,0xe0,0x01,0x08,0x02,0x00,0x04,0x04,0x08,0x07,0x78,0x03,0xf0,0x01,
0xe0,0x01,0x60,0x01,0x20,0x00,0xc0,0x02,0x90,0x04,0x08,0x08,0x04,0xf0,0x03,
0x00,0x40,0x80,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0xc8,0x51,0x0c,0x08,0x0e,
0x01,0x00,0x00,0x37,0x00,0x00,0x00,0x58,0x5f,0x49,0x6d,0x61,0x67,0x65,0x54 };
#define lowcolor_b4b6b4_width 14
#define lowcolor_b4b6b4_height 15
static const unsigned char lowcolor_b4b6b4_bits[] = {
0x00,0x40,0x00,0x00,0x10,0x00,0x08,0x02,0x18,0x06,0xb8,0x47,0x0c,0xce,0x0e,
0xd8,0x06,0x58,0x02,0x10,0x02,0xd0,0x00,0x80,0x00,0x00,0x10,0x02,0x00,0x00,
0x00,0x40,0x80,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,
0x00,0x08,0x00,0x02,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x38,0x5b,0x0c,0x08 };
#define lowcolor_e6e6e6_width 14
#define lowcolor_e6e6e6_height 15
static const unsigned char lowcolor_e6e6e6_bits[] = {
0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x01,0x00,0x00,0x00,0x40,0x00,0xc0,0x00,
0xc0,0x00,0x40,0xe0,0xc0,0xe0,0xc1,0xe0,0x81,0xf0,0x03,0xc0,0x00,0x00,0x00,
0x00,0x40,0x80,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x08,0x19,0x0d,0x08,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00 };

View file

@ -0,0 +1,17 @@
########### next target ###############
set(kwin_modernsys_config_PART_SRCS config.cpp )
kde4_automoc(kwin_modernsys_config ${kwin_modernsys_config_PART_SRCS})
kde4_add_plugin(kwin_modernsys_config ${kwin_modernsys_config_PART_SRCS})
target_link_libraries(kwin_modernsys_config ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY})
install(TARGETS kwin_modernsys_config DESTINATION ${PLUGIN_INSTALL_DIR} )

View file

@ -0,0 +1,140 @@
// Melchior FRANZ <mfranz@kde.org> -- 2001-04-22
#include <kapplication.h>
#include <kconfig.h>
#include <kdialog.h>
#include <klocale.h>
#include <kglobal.h>
#include <QLayout>
//Added by qt3to4:
#include <QLabel>
#include <QVBoxLayout>
#include <QGridLayout>
#include <kvbox.h>
#include "config.h"
extern "C"
{
KDE_EXPORT QObject* allocate_config(KConfig* conf, QWidget* parent)
{
return(new ModernSysConfig(conf, parent));
}
}
// 'conf' is a pointer to the kwindecoration modules open kwin config,
// and is by default set to the "Style" group.
//
// 'parent' is the parent of the QObject, which is a VBox inside the
// Configure tab in kwindecoration
ModernSysConfig::ModernSysConfig(KConfig* conf, QWidget* parent) : QObject(parent)
{
clientrc = new KConfig("kwinmodernsysrc");
KGlobal::locale()->insertCatalog("kwin_clients");
mainw = new QWidget(parent);
vbox = new QVBoxLayout(mainw);
vbox->setSpacing(6);
vbox->setMargin(0);
handleBox = new QWidget(mainw);
QGridLayout* layout = new QGridLayout(handleBox );
layout->setSpacing( KDialog::spacingHint() );
cbShowHandle = new QCheckBox(i18n("&Show window resize handle"), handleBox);
cbShowHandle->setWhatsThis(
i18n("When selected, all windows are drawn with a resize "
"handle at the lower right corner. This makes window resizing "
"easier, especially for trackballs and other mouse replacements "
"on laptops."));
layout->addWidget(cbShowHandle, 0, 0, 1, 2 );
connect(cbShowHandle, SIGNAL(clicked()), this, SLOT(slotSelectionChanged()));
sliderBox = new KVBox(handleBox);
//handleSizeSlider = new QSlider(0, 4, 1, 0, Qt::Horizontal, sliderBox);
handleSizeSlider = new QSlider(Qt::Horizontal, sliderBox);
handleSizeSlider->setMinimum(0);
handleSizeSlider->setMaximum(4);
handleSizeSlider->setPageStep(1);
handleSizeSlider->setWhatsThis(
i18n("Here you can change the size of the resize handle."));
handleSizeSlider->setTickInterval(1);
handleSizeSlider->setTickPosition(QSlider::TicksBelow);
connect(handleSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(slotSelectionChanged()));
hbox = new KHBox(sliderBox);
hbox->setSpacing(6);
bool rtl = kapp->layoutDirection() == Qt::RightToLeft;
label1 = new QLabel(i18n("Small"), hbox);
label1->setAlignment(rtl ? Qt::AlignRight : Qt::AlignLeft);
label2 = new QLabel(i18n("Medium"), hbox);
label2->setAlignment( Qt::AlignHCenter );
label3 = new QLabel(i18n("Large"), hbox);
label3->setAlignment(rtl ? Qt::AlignLeft : Qt::AlignRight);
vbox->addWidget(handleBox);
vbox->addStretch(1);
// layout->setColumnMinimumWidth(0, 30);
layout->addItem(new QSpacerItem(30, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0);
layout->addWidget(sliderBox, 1, 1);
load(conf);
mainw->show();
}
ModernSysConfig::~ModernSysConfig()
{
delete mainw;
delete clientrc;
}
void ModernSysConfig::slotSelectionChanged()
{
bool i = cbShowHandle->isChecked();
if (i != hbox->isEnabled()) {
hbox->setEnabled(i);
handleSizeSlider->setEnabled(i);
}
emit changed();
}
void ModernSysConfig::load(KConfig* /*conf*/)
{
KConfigGroup cg(clientrc, "General");
bool i = cg.readEntry("ShowHandle", true);
cbShowHandle->setChecked(i);
hbox->setEnabled(i);
handleSizeSlider->setEnabled(i);
handleWidth = cg.readEntry("HandleWidth", 6);
handleSize = cg.readEntry("HandleSize", 30);
handleSizeSlider->setValue(qMin((handleWidth - 6) / 2, (uint)4));
}
void ModernSysConfig::save(KConfig* /*conf*/)
{
KConfigGroup cg(clientrc, "General");
cg.writeEntry("ShowHandle", cbShowHandle->isChecked());
cg.writeEntry("HandleWidth", 6 + 2 * handleSizeSlider->value());
cg.writeEntry("HandleSize", 30 + 4 * handleSizeSlider->value());
clientrc->sync();
}
void ModernSysConfig::defaults()
{
cbShowHandle->setChecked(true);
hbox->setEnabled(true);
handleSizeSlider->setEnabled(true);
handleSizeSlider->setValue(0);
}
#include "config.moc"

View file

@ -0,0 +1,52 @@
#ifndef __KDE_MODSYSTEMCONFIG_H
#define __KDE_MODSYSTEMCONFIG_H
#include <QCheckBox>
#include <QLayout>
#include <QSlider>
#include <QLabel>
//Added by qt3to4:
#include <QVBoxLayout>
#include <kvbox.h>
class ModernSysConfig : public QObject
{
Q_OBJECT
public:
ModernSysConfig(KConfig* conf, QWidget* parent);
~ModernSysConfig();
// These public signals/slots work similar to KCM modules
signals:
void changed();
public slots:
void load(KConfig* conf);
void save(KConfig* conf);
void defaults();
protected slots:
void slotSelectionChanged(); // Internal use
private:
KConfig *clientrc;
QWidget *mainw;
QVBoxLayout *vbox;
QWidget *handleBox;
QCheckBox *cbShowHandle;
KVBox *sliderBox;
QSlider *handleSizeSlider;
KHBox *hbox;
QLabel *label1;
QLabel *label2;
QLabel *label3;
unsigned handleWidth;
unsigned handleSize;
};
#endif

View file

@ -0,0 +1,757 @@
// Daniel M. DULEY <mosfet@kde.org> original work
// Melchior FRANZ <a8603365@unet.univie.ac.at> configuration options
#include <kconfig.h>
#include <kglobal.h>
#include <klocale.h>
#include <QLayout>
#include <qdrawutil.h>
//Added by qt3to4:
#include <QPixmap>
#include <QPaintEvent>
#include <kpixmapeffect.h>
#include <QPixmap>
#include <kdrawutil.h>
#include <QBitmap>
#include <QApplication>
#include <QLabel>
#include "modernsys.h"
#include "buttondata.h"
#include "btnhighcolor.h"
#include <QImage>
namespace ModernSystem {
static unsigned char iconify_bits[] = {
0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00};
static unsigned char close_bits[] = {
0x00, 0x66, 0x7e, 0x3c, 0x3c, 0x7e, 0x66, 0x00};
static unsigned char maximize_bits[] = {
0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00};
static unsigned char r_minmax_bits[] = {
0x0c, 0x18, 0x33, 0x67, 0xcf, 0x9f, 0x3f, 0x3f};
static unsigned char l_minmax_bits[] = {
0x30, 0x18, 0xcc, 0xe6, 0xf3, 0xf9, 0xfc, 0xfc};
static unsigned char unsticky_bits[] = {
0x3c, 0x42, 0x99, 0xbd, 0xbd, 0x99, 0x42, 0x3c};
static unsigned char sticky_bits[] = {
0x3c, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3c};
static unsigned char question_bits[] = {
0x3c, 0x66, 0x60, 0x30, 0x18, 0x00, 0x18, 0x18};
static unsigned char above_on_bits[] = {
0x7e, 0x00, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00};
static unsigned char above_off_bits[] = {
0x18, 0x3c, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00};
static unsigned char below_off_bits[] = {
0x00, 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x3c, 0x18};
static unsigned char below_on_bits[] = {
0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x00, 0x7e};
static unsigned char shade_off_bits[] = {
0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00};
static unsigned char shade_on_bits[] = {
0x00, 0x7e, 0x7e, 0x42, 0x42, 0x42, 0x7e, 0x00};
static unsigned char menu_bits[] = {
0xff, 0x81, 0x81, 0xff, 0x81, 0xff, 0x81, 0xff};
static unsigned char btnhighcolor_mask_bits[] = {
0xe0,0x41,0xf8,0x07,0xfc,0x0f,0xfe,0xdf,0xfe,0x1f,0xff,0x3f,0xff,0xff,0xff,
0x3f,0xff,0x3f,0xff,0xff,0xff,0xff,0xfe,0x9f,0xfe,0x1f,0xfc,0x0f,0xf0,0x03,
0x00,0x40,0x80,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x20,0x99,0x0f,0x08,0xc4,
0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x58,0x5f,0x43,0x68,0x61,0x6e,0x67,0x65 };
static QPixmap *aUpperGradient=0;
static QPixmap *iUpperGradient=0;
static QPixmap *buttonPix=0;
static QPixmap *buttonPixDown=0;
static QPixmap *iButtonPix=0;
static QPixmap *iButtonPixDown=0;
static QColor *buttonFg;
static bool pixmaps_created = false;
static QBitmap *lcDark1;
static QBitmap *lcDark2;
static QBitmap *lcDark3;
static QBitmap *lcLight1;
static QImage *btnSource;
static bool show_handle;
static int handle_size;
static int handle_width;
static int border_width;
static int title_height;
static inline const KDecorationOptions* options()
{
return KDecoration::options();
}
static void make_button_fx(const QPalette &g, QPixmap *pix, bool light=false)
{
pix->fill(g.background().color());
QPainter p(pix);
if(QPixmap::defaultDepth() > 8){
int i, destH, destS, destV, srcH, srcS, srcV;
QColor btnColor = g.background().color();
if(btnSource->depth() < 32)
*btnSource = btnSource->convertDepth(32);
if(light)
btnColor = btnColor.light(120);
btnColor.getHsv(&destH, &destS, &destV);
QImage btnDest(14, 15, 32);
unsigned int *srcData = (unsigned int *)btnSource->bits();
unsigned int *destData = (unsigned int *)btnDest.bits();
QColor srcColor;
for(i=0; i < btnSource->width()*btnSource->height(); ++i){
srcColor.setRgb(srcData[i]);
srcColor.getHsv(&srcH, &srcS, &srcV);
srcColor.setHsv(destH, destS, srcV);
destData[i] = srcColor.rgb();
}
*pix = QPixmap::fromImage(btnDest);
}
else{
if(!lcDark1->mask()){
lcDark1->setMask(*lcDark1);
lcDark2->setMask(*lcDark2);
lcDark3->setMask(*lcDark3);
lcLight1->setMask(*lcLight1);
}
p.setPen(g.dark().color());
p.drawPixmap(0, 0, *lcDark2);
p.drawPixmap(0, 0, *lcDark1);
p.setPen(g.mid().color());
p.drawPixmap(0, 0, *lcDark3);
p.setPen(g.light().color());
p.drawPixmap(0, 0, *lcLight1);
}
}
static void create_pixmaps()
{
if(pixmaps_created)
return;
pixmaps_created = true;
lcDark1 = new QBitmap(14, 15, lowcolor_6a696a_bits, true);
lcDark2 = new QBitmap(14, 15, lowcolor_949194_bits, true);
lcDark3 = new QBitmap(14, 15, lowcolor_b4b6b4_bits, true);
lcLight1 = new QBitmap(14, 15, lowcolor_e6e6e6_bits, true);
btnSource = new QImage(btnhighcolor_xpm);
if(QPixmap::defaultDepth() > 8){
aUpperGradient = new QPixmap( 32, title_height+2 );
iUpperGradient = new QPixmap( 32, title_height+2);;
KPixmapEffect::gradient(*aUpperGradient,
options()->color(KDecoration::ColorTitleBar, true).light(130),
options()->color(KDecoration::ColorTitleBlend, true),
KPixmapEffect::VerticalGradient);
KPixmapEffect::gradient(*iUpperGradient,
options()->color(KDecoration::ColorTitleBar, false).light(130),
options()->color(KDecoration::ColorTitleBlend, false),
KPixmapEffect::VerticalGradient);
}
// buttons
QPalette btnColor(options()->palette(KDecoration::ColorButtonBg, true) );
btnColor.setCurrentColorGroup(QPalette::Active);
buttonPix = new QPixmap(14, 15);
make_button_fx(btnColor, buttonPix);
buttonPixDown = new QPixmap(14, 15);
make_button_fx(btnColor, buttonPixDown, true);
btnColor = options()->palette(KDecoration::ColorButtonBg, false);
btnColor.setCurrentColorGroup(QPalette::Active);
iButtonPix = new QPixmap(14, 15);
make_button_fx(btnColor, iButtonPix);
iButtonPixDown = new QPixmap(14, 15);
make_button_fx(btnColor, iButtonPixDown, true);
if(qGray(btnColor.background().color().rgb()) < 150)
buttonFg = new QColor(Qt::white);
else
buttonFg = new QColor(Qt::black);
delete lcDark1;
delete lcDark2;
delete lcDark3;
delete lcLight1;
delete btnSource;
}
static void delete_pixmaps()
{
if(aUpperGradient){
delete aUpperGradient;
delete iUpperGradient;
}
delete buttonPix;
delete buttonPixDown;
delete iButtonPix;
delete iButtonPixDown;
delete buttonFg;
pixmaps_created = false;
}
void ModernSysFactory::read_config()
{
bool showh;
int hsize, hwidth, bwidth, theight;
KConfig _c( "kwinmodernsysrc" );
KConfigGroup c(&_c, "General");
showh = c.readEntry("ShowHandle", true);
hwidth = c.readEntry("HandleWidth", 6);
hsize = c.readEntry("HandleSize", 30);
if (!(showh && hsize && hwidth)) {
showh = false;
hwidth = hsize = 0;
}
switch(options()->preferredBorderSize( this )) {
case BorderLarge:
bwidth = 8;
hwidth = hwidth * 7/5;
hsize = hsize * 7/5;
break;
case BorderVeryLarge:
bwidth = 12;
hwidth = hwidth * 17/10 + 2;
hsize = hsize * 17/10;
break;
case BorderHuge:
bwidth = 18;
hwidth = hwidth * 2 + 6;
hsize = hsize * 2;
break;
/*
// If we allow these large sizes we need to change the
// correlation between the border width and the handle size.
case BorderVeryHuge:
bwidth = 27;
hwidth = hwidth * 5/2 + 15;
hsize = hsize * 5/2;
break;
case BorderOversized:
bwidth = 40;
hwidth = hwidth * 3 + 22;
hsize = hsize * 3;
break;
*/
case BorderNormal:
default:
bwidth = 4;
}
theight = QFontMetrics(options()->font(true)).height() + 2;
if (theight < 16)
theight = 16;
if (theight < bwidth)
theight = bwidth;
show_handle = showh;
handle_width = hwidth;
handle_size = hsize;
border_width = bwidth;
title_height = theight;
}
QList< ModernSysFactory::BorderSize > ModernSysFactory::borderSizes() const
{ // the list must be sorted
return QList< BorderSize >() << BorderNormal << BorderLarge <<
BorderVeryLarge << BorderHuge;
// as long as the buttons don't scale don't offer the largest two sizes.
// BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
}
ModernButton::ModernButton(ButtonType type, ModernSys *parent, const char *name)
: KCommonDecorationButton(type, parent)
{
setObjectName( name );
setAttribute(Qt::WA_NoSystemBackground, true);
QBitmap mask(14, 15, QPixmap::defaultDepth() > 8 ?
btnhighcolor_mask_bits : lowcolor_mask_bits, true);
resize(14, 15);
setMask(mask);
}
void ModernButton::reset(unsigned long changed)
{
if (changed&DecorationReset || changed&ManualReset || changed&SizeChange || changed&StateChange) {
switch (type() ) {
case CloseButton:
setBitmap(close_bits);
break;
case HelpButton:
setBitmap(question_bits);
break;
case MinButton:
setBitmap(iconify_bits);
break;
case MaxButton:
setBitmap( isChecked() ? (isLeft()?l_minmax_bits:r_minmax_bits) : maximize_bits );
break;
case OnAllDesktopsButton:
setBitmap( isChecked() ? unsticky_bits : sticky_bits );
break;
case ShadeButton:
setBitmap( isChecked() ? shade_on_bits : shade_off_bits );
break;
case AboveButton:
setBitmap( isChecked() ? above_on_bits : above_off_bits );
break;
case BelowButton:
setBitmap( isChecked() ? below_on_bits : below_off_bits );
break;
case MenuButton:
setBitmap(menu_bits);
break;
default:
setBitmap(0);
break;
}
this->update();
}
}
void ModernButton::setBitmap(const unsigned char *bitmap)
{
if (bitmap)
deco = QBitmap(8, 8, bitmap, true);
else {
deco = QBitmap(8,8);
deco.fill(Qt::color0);
}
deco.setMask(deco);
}
void ModernButton::paintEvent(QPaintEvent *)
{
QPainter p(this);
drawButton(&p);
}
void ModernButton::drawButton(QPainter *p)
{
if(decoration()->isActive()){
if(buttonPix)
p->drawPixmap(0, 0, isDown() ? *buttonPixDown : *buttonPix);
}
else{
if(iButtonPix)
p->drawPixmap(0, 0, isDown() ? *iButtonPixDown : *iButtonPix);
}
if(!deco.isNull()){
p->setPen(*buttonFg);
p->drawPixmap(isDown() ? 4 : 3, isDown() ? 5 : 4, deco);
}
}
void ModernSys::reset( unsigned long changed)
{
KCommonDecoration::reset(changed);
titleBuffer = QPixmap();
recalcTitleBuffer();
resetButtons();
widget()->update();
}
ModernSys::ModernSys( KDecorationBridge* b, KDecorationFactory* f )
: KCommonDecoration( b, f )
{
}
QString ModernSys::visibleName() const
{
return i18n("Modern System");
}
QString ModernSys::defaultButtonsLeft() const
{
return "X";
}
QString ModernSys::defaultButtonsRight() const
{
return "HSIA";
}
bool ModernSys::decorationBehaviour(DecorationBehaviour behaviour) const
{
switch (behaviour) {
case DB_MenuClose:
return false;
case DB_WindowMask:
return true;
case DB_ButtonHide:
return true;
default:
return KCommonDecoration::decorationBehaviour(behaviour);
}
}
int ModernSys::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const
{
// bool maximized = maximizeMode()==MaximizeFull && !options()->moveResizeMaximizedWindows();
switch (lm) {
case LM_BorderLeft:
return border_width + (reverse ? handle_width : 0);
case LM_BorderRight:
return border_width + (reverse ? 0 : handle_width);
case LM_BorderBottom:
return border_width + handle_width;
case LM_TitleEdgeLeft:
return layoutMetric(LM_BorderLeft,respectWindowState)+3;
case LM_TitleEdgeRight:
return layoutMetric(LM_BorderRight,respectWindowState)+3;
case LM_TitleEdgeTop:
return 2;
case LM_TitleEdgeBottom:
return 2;
case LM_TitleBorderLeft:
case LM_TitleBorderRight:
return 4;
case LM_TitleHeight:
return title_height;
case LM_ButtonWidth:
return 14;
case LM_ButtonHeight:
return 15;
case LM_ButtonSpacing:
return 1;
case LM_ExplicitButtonSpacer:
return 3;
default:
return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
}
}
KCommonDecorationButton *ModernSys::createButton(ButtonType type)
{
switch (type) {
case MenuButton:
return new ModernButton(MenuButton, this, "menu");
case OnAllDesktopsButton:
return new ModernButton(OnAllDesktopsButton, this, "on_all_desktops");
case HelpButton:
return new ModernButton(HelpButton, this, "help");
case MinButton:
return new ModernButton(MinButton, this, "minimize");
case MaxButton:
return new ModernButton(MaxButton, this, "maximize");
case CloseButton:
return new ModernButton(CloseButton, this, "close");
case AboveButton:
return new ModernButton(AboveButton, this, "above");
case BelowButton:
return new ModernButton(BelowButton, this, "below");
case ShadeButton:
return new ModernButton(ShadeButton, this, "shade");
default:
return 0;
}
}
void ModernSys::init()
{
reverse = QApplication::isRightToLeft();
KCommonDecoration::init();
recalcTitleBuffer();
}
void ModernSys::recalcTitleBuffer()
{
if(oldTitle == caption() && width() == titleBuffer.width())
return;
QFontMetrics fm(options()->font(true));
titleBuffer = QPixmap(width(), title_height+2);
QPainter p;
p.begin(&titleBuffer);
QPalette pt = options()->palette(ColorTitleBar, true);
pt.setCurrentColorGroup( QPalette::Active );
if(aUpperGradient)
p.drawTiledPixmap(0, 0, width(), title_height+2, *aUpperGradient);
else
p.fillRect(0, 0, width(), title_height+2,
pt.brush(QPalette::Button));
QRect t = titleRect(); // titlebar->geometry();
t.setTop( 2 );
t.setLeft( t.left() );
t.setRight( t.right() - 2 );
QRegion r(t.x(), 0, t.width(), title_height+2);
r -= QRect(t.x()+((t.width()-fm.width(caption()))/2)-4,
0, fm.width(caption())+8, title_height+2);
p.setClipRegion(r);
int i, ly;
ly = (title_height % 3 == 0) ? 3 : 4;
for(i=0; i < (title_height-2)/3; ++i, ly+=3){
p.setPen(options()->color(ColorTitleBar, true).light(150));
p.drawLine(0, ly, width()-1, ly);
p.setPen(options()->color(ColorTitleBar, true).dark(120));
p.drawLine(0, ly+1, width()-1, ly+1);
}
p.setClipRect(t);
p.setPen(options()->color(ColorFont, true));
p.setFont(options()->font(true));
p.drawText(t.x()+((t.width()-fm.width(caption()))/2)-4,
0, fm.width(caption())+8, title_height+2, Qt::AlignCenter, caption());
p.setClipping(false);
p.end();
oldTitle = caption();
}
void ModernSys::updateCaption()
{
widget()->update(titleRect() );
}
void ModernSys::drawRoundFrame(QPainter &p, int x, int y, int w, int h)
{
QPalette pt = options()->palette(ColorFrame, isActive());
pt.setCurrentColorGroup( QPalette::Active );
kDrawRoundButton(&p, x, y, w, h,
pt, false);
}
void ModernSys::paintEvent( QPaintEvent* )
{
// update title buffer...
if (oldTitle != caption() || width() != titleBuffer.width() )
recalcTitleBuffer();
int hs = handle_size;
int hw = handle_width;
QPainter p( widget() );
QRect t = titleRect(); // titlebar->geometry();
QPalette pt = options()->palette(ColorFrame, isActive());
pt.setCurrentColorGroup( QPalette::Active );
QBrush fillBrush(widget()->palette().brush(QPalette::Background).pixmap() ?
widget()->palette().brush(QPalette::Background) :
pt.brush(QPalette::Button));
p.fillRect(1, title_height+3, width()-2, height()-(title_height+3), fillBrush);
p.fillRect(width()-6, 0, width()-1, height(), fillBrush);
t.setTop( 2 );
t.setLeft( t.left() );
t.setRight( t.right() - 2 );
int w = width() - hw; // exclude handle
int h = height() - hw;
// titlebar
QPalette g = options()->palette(ColorTitleBar, isActive());
g.setCurrentColorGroup( QPalette::Active );
if(isActive()){
p.drawPixmap(1, 1, titleBuffer, 0, 0, w-2, title_height+2);
}
else{
if(iUpperGradient)
p.drawTiledPixmap(1, 1, w-2, title_height+2, *iUpperGradient);
else
p.fillRect(1, 1, w-2, title_height+2, fillBrush);
p.setPen(options()->color(ColorFont, isActive()));
p.setFont(options()->font(isActive()));
p.drawText(t, Qt::AlignCenter, caption() );
}
// titlebar highlight
p.setPen(g.light().color());
p.drawLine(1, 1, 1, title_height+3);
p.drawLine(1, 1, w-3, 1);
p.setPen(g.dark().color());
p.drawLine(w-2, 1, w-2, title_height+3);
p.drawLine(0, title_height+2, w-2, title_height+2);
// frame
g = options()->palette(ColorFrame, isActive());
g.setCurrentColorGroup(QPalette::Active);
p.setPen(g.light().color());
p.drawLine(1, title_height+3, 1, h-2);
p.setPen(g.dark().color());
p.drawLine(2, h-2, w-2, h-2);
p.drawLine(w-2, title_height+3, w-2, h-2);
//p.drawPoint(w-3, title_height+3);
//p.drawPoint(2, title_height+3);
qDrawShadePanel(&p, border_width-1, title_height+3, w-2*border_width+2, h-title_height-border_width-2, g, true);
if (show_handle) {
p.setPen(g.dark().color());
p.drawLine(width()-3, height()-hs-1, width()-3, height()-3);
p.drawLine(width()-hs-1, height()-3, width()-3, height()-3);
p.setPen(g.light().color());
p.drawLine(width()-hw, height()-hs-1, width()-hw, height()-hw);
p.drawLine(width()-hs-1, height()-hw, width()-hw, height()-hw);
p.drawLine(width()-hw, height()-hs-1, width()-4, height()-hs-1);
p.drawLine(width()-hs-1, height()-hw, width()-hs-1, height()-4);
p.setPen(Qt::black);
p.drawRect(0, 0, w, h);
// handle outline
p.drawLine(width()-hw, height()-hs, width(), height()-hs);
p.drawLine(width()-2, height()-hs, width()-2, height()-2);
p.drawLine(width()-hs, height()-2, width()-2, height()-2);
p.drawLine(width()-hs, height()-hw, width()-hs, height()-2);
} else {
p.setPen(Qt::black);
p.drawRect(0, 0, w, h);
}
}
void ModernSys::updateWindowShape()
{
int hs = handle_size;
int hw = handle_width;
QRegion mask;
mask += QRect(0, 0, width()-hw, height()-hw);
//single points
mask -= QRect(0, 0, 1, 1);
mask -= QRect(width()-hw-1, 0, 1, 1);
mask -= QRect(0, height()-hw-1, 1, 1);
if (show_handle) {
mask += QRect(width()-hs, height()-hs, hs-1, hs-1);
mask -= QRect(width()-2, height()-2, 1, 1);
mask -= QRect(width()-2, height()-hs, 1, 1);
mask -= QRect(width()-hs, height()-2, 1, 1);
} else
mask -= QRect(width()-1, height()-1, 1, 1);
setMask(mask);
}
ModernSysFactory::ModernSysFactory()
{
read_config();
create_pixmaps();
}
ModernSysFactory::~ModernSysFactory()
{
ModernSystem::delete_pixmaps();
}
KDecoration* ModernSysFactory::createDecoration( KDecorationBridge* b )
{
return(new ModernSys(b, this));
}
bool ModernSysFactory::reset( unsigned long changed )
{
read_config();
bool needHardReset = true;
if( changed & (SettingColors | SettingBorder | SettingFont) )
{
delete_pixmaps();
create_pixmaps();
needHardReset = false;
} else if (changed & SettingButtons) {
// handled by KCommonDecoration
needHardReset = false;
}
if( needHardReset )
return true;
else
{
resetDecorations( changed );
return false; // no recreating of decorations
}
}
bool ModernSysFactory::supports( Ability ability )
{
switch( ability )
{
case AbilityAnnounceButtons:
case AbilityButtonOnAllDesktops:
case AbilityButtonSpacer:
case AbilityButtonHelp:
case AbilityButtonMinimize:
case AbilityButtonMaximize:
case AbilityButtonClose:
case AbilityButtonAboveOthers:
case AbilityButtonBelowOthers:
case AbilityButtonShade:
case AbilityButtonMenu:
return true;
default:
return false;
};
}
}
// KWin extended plugin interface
extern "C" KDE_EXPORT KDecorationFactory* create_factory()
{
return new ModernSystem::ModernSysFactory();
}
// vim:ts=4:sw=4

View file

@ -0,0 +1,71 @@
#ifndef __MODSYSTEMCLIENT_H
#define __MODSYSTEMCLIENT_H
#include <QBitmap>
#include <kcommondecoration.h>
#include <kdecorationfactory.h>
class QLabel;
class QSpacerItem;
namespace ModernSystem {
class ModernSys;
class ModernButton : public KCommonDecorationButton
{
public:
ModernButton(ButtonType type, ModernSys *parent, const char *name);
void setBitmap(const unsigned char *bitmap);
virtual void reset(unsigned long changed);
protected:
void paintEvent(QPaintEvent *);
virtual void drawButton(QPainter *p);
void drawButtonLabel(QPainter *){;}
QBitmap deco;
};
class ModernSys : public KCommonDecoration
{
public:
ModernSys( KDecorationBridge* b, KDecorationFactory* f );
~ModernSys(){;}
virtual QString visibleName() const;
virtual QString defaultButtonsLeft() const;
virtual QString defaultButtonsRight() const;
virtual bool decorationBehaviour(DecorationBehaviour behaviour) const;
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
virtual KCommonDecorationButton *createButton(ButtonType type);
virtual void updateWindowShape();
virtual void updateCaption();
void init();
protected:
void drawRoundFrame(QPainter &p, int x, int y, int w, int h);
void paintEvent( QPaintEvent* );
void recalcTitleBuffer();
void reset( unsigned long );
private:
QPixmap titleBuffer;
QString oldTitle;
bool reverse;
};
class ModernSysFactory : public QObject, public KDecorationFactory
{
public:
ModernSysFactory();
virtual ~ModernSysFactory();
virtual KDecoration* createDecoration( KDecorationBridge* );
virtual bool reset( unsigned long changed );
virtual bool supports( Ability ability );
QList< BorderSize > borderSizes() const;
private:
void read_config();
};
}
#endif

View file

@ -0,0 +1,6 @@
[Desktop Entry]
Encoding=UTF-8
Name=Modern System
Name[fr]=Système Moderne
Name[x-test]=xxModern Systemxx
X-KDE-Library=kwin3_modernsys

View file

@ -0,0 +1,29 @@
add_subdirectory( config )
include_directories( ${CMAKE_SOURCE_DIR}/workspace/kwin/lib )
########### next target ###############
set(kwin3_plastik_PART_SRCS
plastik.cpp
plastikclient.cpp
plastikbutton.cpp
misc.cpp )
kde4_automoc(kwin3_plastik ${kwin3_plastik_PART_SRCS})
kde4_add_plugin(kwin3_plastik ${kwin3_plastik_PART_SRCS})
target_link_libraries(kwin3_plastik ${KDE4_KDEUI_LIBS} kdecorations kdefx)
install(TARGETS kwin3_plastik DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES plastik.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin/ )

View file

@ -0,0 +1,19 @@
########### next target ###############
set(kwin_plastik_config_PART_SRCS config.cpp )
kde4_automoc(kwin_plastik_config ${kwin_plastik_config_PART_SRCS})
kde4_add_ui3_files(kwin_plastik_config_PART_SRCS configdialog.ui )
kde4_add_plugin(kwin_plastik_config ${kwin_plastik_config_PART_SRCS})
target_link_libraries(kwin_plastik_config ${KDE4_KDEUI_LIBS} ${QT_QTGUI_LIBRARY} ${QT_QT3SUPPORT_LIBRARY})
install(TARGETS kwin_plastik_config DESTINATION ${PLUGIN_INSTALL_DIR} )

View file

@ -0,0 +1,122 @@
/* Plastik KWin window decoration
Copyright (C) 2003 Sandro Giessl <ceebx@users.sourceforge.net>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QButtonGroup>
#include <QCheckBox>
#include <QRadioButton>
#include <QSlider>
#include <QSpinBox>
#include <QWhatsThis>
#include <kconfig.h>
#include <klocale.h>
#include <kglobal.h>
#include "config.h"
#include "configdialog.h"
PlastikConfig::PlastikConfig(KConfig* config, QWidget* parent)
: QObject(parent), m_config(0), m_dialog(0)
{
// create the configuration object
m_config = new KConfig("kwinplastikrc");
KGlobal::locale()->insertCatalog("kwin_clients");
// create and show the configuration dialog
m_dialog = new ConfigDialog(parent);
m_dialog->show();
// load the configuration
load(config);
// setup the connections
connect(m_dialog->titleAlign, SIGNAL(clicked(int)),
this, SIGNAL(changed()));
connect(m_dialog->animateButtons, SIGNAL(toggled(bool)),
this, SIGNAL(changed()));
connect(m_dialog->menuClose, SIGNAL(toggled(bool)),
this, SIGNAL(changed()));
connect(m_dialog->titleShadow, SIGNAL(toggled(bool)),
this, SIGNAL(changed()));
connect(m_dialog->coloredBorder, SIGNAL(toggled(bool)),
this, SIGNAL(changed()));
}
PlastikConfig::~PlastikConfig()
{
if (m_dialog) delete m_dialog;
if (m_config) delete m_config;
}
void PlastikConfig::load(KConfig*)
{
KConfigGroup cg(m_config, "General");
QString value = cg.readEntry("TitleAlignment", "AlignLeft");
QRadioButton *button = m_dialog->titleAlign->findChild<QRadioButton*>(value.toLatin1());
if (button) button->setChecked(true);
bool animateButtons = cg.readEntry("AnimateButtons", true);
m_dialog->animateButtons->setChecked(animateButtons);
bool menuClose = cg.readEntry("CloseOnMenuDoubleClick", true);
m_dialog->menuClose->setChecked(menuClose);
bool titleShadow = cg.readEntry("TitleShadow", true);
m_dialog->titleShadow->setChecked(titleShadow);
bool coloredBorder = cg.readEntry("ColoredBorder", true);
m_dialog->coloredBorder->setChecked(coloredBorder);
}
void PlastikConfig::save(KConfig*)
{
KConfigGroup cg(m_config, "General");
QRadioButton *button = (QRadioButton*)m_dialog->titleAlign->selected();
if (button) cg.writeEntry("TitleAlignment", QString(button->objectName()));
cg.writeEntry("AnimateButtons", m_dialog->animateButtons->isChecked() );
cg.writeEntry("CloseOnMenuDoubleClick", m_dialog->menuClose->isChecked() );
cg.writeEntry("TitleShadow", m_dialog->titleShadow->isChecked() );
cg.writeEntry("ColoredBorder", m_dialog->coloredBorder->isChecked() );
m_config->sync();
}
void PlastikConfig::defaults()
{
QRadioButton *button = m_dialog->titleAlign->findChild<QRadioButton*>("AlignLeft");
if (button) button->setChecked(true);
m_dialog->animateButtons->setChecked(true);
m_dialog->menuClose->setChecked(false);
m_dialog->titleShadow->setChecked(true);
m_dialog->coloredBorder->setChecked(true);
}
//////////////////////////////////////////////////////////////////////////////
// Plugin Stuff //
//////////////////////////////////////////////////////////////////////////////
extern "C"
{
KDE_EXPORT QObject* allocate_config(KConfig* config, QWidget* parent) {
return (new PlastikConfig(config, parent));
}
}
#include "config.moc"

View file

@ -0,0 +1,53 @@
/* Plastik KWin window decoration
Copyright (C) 2003 Sandro Giessl <ceebx@users.sourceforge.net>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KNIFTYCONFIG_H
#define KNIFTYCONFIG_H
#include <QObject>
class QButtonGroup;
class QGroupBox;
class KConfig;
class ConfigDialog;
class PlastikConfig : public QObject
{
Q_OBJECT
public:
PlastikConfig(KConfig* config, QWidget* parent);
~PlastikConfig();
signals:
void changed();
public slots:
void load(KConfig *config);
void save(KConfig *config);
void defaults();
private:
KConfig *m_config;
ConfigDialog *m_dialog;
};
#endif // KNIFTYCONFIG_H

View file

@ -0,0 +1,119 @@
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>ConfigDialog</class>
<widget class="QWidget">
<property name="name">
<cstring>ConfigDialog</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>541</width>
<height>170</height>
</rect>
</property>
<property name="windowTitle">
<string>Config Dialog</string>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="margin">
<number>0</number>
</property>
<widget class="QButtonGroup">
<property name="name">
<cstring>titleAlign</cstring>
</property>
<property name="title">
<string>Title &amp;Alignment</string>
</property>
<hbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QRadioButton">
<property name="name">
<cstring>AlignLeft</cstring>
</property>
<property name="text">
<string>Left</string>
</property>
</widget>
<widget class="QRadioButton">
<property name="name">
<cstring>AlignHCenter</cstring>
</property>
<property name="text">
<string>Center</string>
</property>
</widget>
<widget class="QRadioButton">
<property name="name">
<cstring>AlignRight</cstring>
</property>
<property name="text">
<string>Right</string>
</property>
</widget>
</hbox>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>coloredBorder</cstring>
</property>
<property name="text">
<string>Colored Window Border</string>
</property>
<property name="accel">
<string></string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if the window border should be painted in the titlebar color. Otherwise it will be painted in the background color.</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>titleShadow</cstring>
</property>
<property name="text">
<string>Use shadowed &amp;text</string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if you want the titlebar text to have a 3D look with a shadow behind it.</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>animateButtons</cstring>
</property>
<property name="text">
<string>Animate buttons</string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if you want the buttons to fade in when the mouse pointer hovers over them and fade out again when it moves away.</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>menuClose</cstring>
</property>
<property name="text">
<string>Close windows by double clicking the menu button</string>
</property>
<property name="whatsThis" stdset="0">
<string>Check this option if you want windows to be closed when you double click the menu button, similar to Microsoft Windows.</string>
</property>
</widget>
</vbox>
</widget>
<tabstops>
<tabstop>AlignLeft</tabstop>
<tabstop>AlignHCenter</tabstop>
<tabstop>AlignRight</tabstop>
<tabstop>animateButtons</tabstop>
<tabstop>titleShadow</tabstop>
</tabstops>
<layoutdefaults spacing="6" margin="11"/>
</UI>

83
clients/plastik/misc.cpp Normal file
View file

@ -0,0 +1,83 @@
/* Plastik KWin window decoration
Copyright (C) 2003 Sandro Giessl <ceebx@users.sourceforge.net>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <kpixmapeffect.h>
#include <QColor>
#include <QImage>
#include <QPainter>
#include "misc.h"
QColor hsvRelative(const QColor& baseColor, int relativeH, int relativeS, int relativeV)
{
int h, s, v;
baseColor.getHsv(&h, &s, &v);
h += relativeH;
s += relativeS;
v += relativeV;
if(h < 0) { h = 0; }
else if(h > 359) { h = 359; }
if(s < 0) { s = 0; }
else if(s > 255) { s = 255; }
if(v < 0) { v = 0; }
else if(v > 255) { v = 255; }
QColor c;
c.setHsv( h, s, v );
return c;
}
QColor alphaBlendColors(const QColor &bgColor, const QColor &fgColor, const int a)
{
// normal button...
QRgb rgb = bgColor.rgb();
QRgb rgb_b = fgColor.rgb();
int alpha = a;
if(alpha>255) alpha = 255;
if(alpha<0) alpha = 0;
int inv_alpha = 255 - alpha;
QColor result = QColor( qRgb(qRed(rgb_b)*inv_alpha/255 + qRed(rgb)*alpha/255,
qGreen(rgb_b)*inv_alpha/255 + qGreen(rgb)*alpha/255,
qBlue(rgb_b)*inv_alpha/255 + qBlue(rgb)*alpha/255) );
return result;
}
QImage recolorImage(QImage *img, QColor color) {
QImage destImg(img->width(),img->height(), QImage::Format_ARGB32);
for (int x = 0; x < img->width(); x++) {
for (int y = 0; y < img->height(); y++) {
if(img->pixel(x,y) == qRgb(0,0,255) ) {
destImg.setPixel(x,y,color.rgb() ); // set to the new color
} else {
destImg.setPixel(x,y,qRgba(0,0,0,0) ); // set transparent...
}
}
}
return destImg;
}

30
clients/plastik/misc.h Normal file
View file

@ -0,0 +1,30 @@
/* Plastik KWin window decoration
Copyright (C) 2003 Sandro Giessl <ceebx@users.sourceforge.net>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef MISC_H
#define MISC_H
QColor hsvRelative(const QColor& baseColor, int relativeH, int relativeS = 0, int relativeV = 0);
QColor alphaBlendColors(const QColor &backgroundColor, const QColor &foregroundColor, const int alpha);
QImage recolorImage(QImage *img, QColor color);
#endif // MISC_H

572
clients/plastik/plastik.cpp Normal file
View file

@ -0,0 +1,572 @@
/* Plastik KWin window decoration
Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QBitmap>
#include <QPainter>
#include <QImage>
#include <kconfig.h>
#include <QPixmap>
#include <kpixmapeffect.h>
#include "misc.h"
#include "plastik.h"
#include "plastik.moc"
#include "plastikclient.h"
#include "plastikbutton.h"
#include <QApplication>
namespace KWinPlastik
{
PlastikHandler::PlastikHandler()
{
memset(m_pixmaps, 0, sizeof(QPixmap*)*NumPixmaps*2*2); // set elements to 0
memset(m_bitmaps, 0, sizeof(QBitmap*)*NumButtonIcons*2);
reset(0);
}
PlastikHandler::~PlastikHandler()
{
for (int t=0; t < 2; ++t)
for (int a=0; a < 2; ++a)
for (int i=0; i < NumPixmaps; ++i)
delete m_pixmaps[t][a][i];
for (int t=0; t < 2; ++t)
for (int i=0; i < NumButtonIcons; ++i)
delete m_bitmaps[t][i];
}
bool PlastikHandler::reset(unsigned long changed)
{
// we assume the active font to be the same as the inactive font since the control
// center doesn't offer different settings anyways.
m_titleFont = KDecoration::options()->font(true, false); // not small
m_titleFontTool = KDecoration::options()->font(true, true); // small
switch(KDecoration::options()->preferredBorderSize( this )) {
case BorderTiny:
m_borderSize = 3;
break;
case BorderLarge:
m_borderSize = 8;
break;
case BorderVeryLarge:
m_borderSize = 12;
break;
case BorderHuge:
m_borderSize = 18;
break;
case BorderVeryHuge:
m_borderSize = 27;
break;
case BorderOversized:
m_borderSize = 40;
break;
case BorderNormal:
default:
m_borderSize = 4;
}
// check if we are in reverse layout mode
m_reverse = QApplication::isRightToLeft();
// read in the configuration
readConfig();
// pixmaps probably need to be updated, so delete the cache.
for (int t=0; t < 2; ++t) {
for (int a=0; a < 2; ++a) {
for (int i=0; i < NumPixmaps; i++) {
if (m_pixmaps[t][a][i]) {
delete m_pixmaps[t][a][i];
m_pixmaps[t][a][i] = 0;
}
}
}
}
for (int t=0; t < 2; ++t) {
for (int i=0; i < NumButtonIcons; i++) {
if (m_bitmaps[t][i]) {
delete m_bitmaps[t][i];
m_bitmaps[t][i] = 0;
}
}
}
// Do we need to "hit the wooden hammer" ?
bool needHardReset = true;
// TODO: besides the Color and Font settings I can maybe handle more changes
// without a hard reset. I will do this later...
if (changed & SettingColors || changed & SettingFont)
{
needHardReset = false;
} else if (changed & SettingButtons) {
// handled by KCommonDecoration
needHardReset = false;
}
if (needHardReset) {
return true;
} else {
resetDecorations(changed);
return false;
}
}
KDecoration* PlastikHandler::createDecoration( KDecorationBridge* bridge )
{
return new PlastikClient( bridge, this );
}
bool PlastikHandler::supports( Ability ability )
{
switch( ability )
{
case AbilityAnnounceButtons:
case AbilityButtonMenu:
case AbilityButtonOnAllDesktops:
case AbilityButtonSpacer:
case AbilityButtonHelp:
case AbilityButtonMinimize:
case AbilityButtonMaximize:
case AbilityButtonClose:
case AbilityButtonAboveOthers:
case AbilityButtonBelowOthers:
case AbilityButtonShade:
return true;
default:
return false;
};
}
void PlastikHandler::readConfig()
{
// create a config object
KConfig configFile("kwinplastikrc");
const KConfigGroup config( &configFile, "General");
// grab settings
m_titleShadow = config.readEntry("TitleShadow", true);
QFontMetrics fm(m_titleFont); // active font = inactive font
int titleHeightMin = config.readEntry("MinTitleHeight", 16);
// The title should strech with bigger font sizes!
m_titleHeight = qMax(titleHeightMin, fm.height() + 4); // 4 px for the shadow etc.
// have an even title/button size so the button icons are fully centered...
if ( m_titleHeight%2 == 0)
m_titleHeight++;
fm = QFontMetrics(m_titleFontTool); // active font = inactive font
int titleHeightToolMin = config.readEntry("MinTitleHeightTool", 13);
// The title should strech with bigger font sizes!
m_titleHeightTool = qMax(titleHeightToolMin, fm.height() ); // don't care about the shadow etc.
// have an even title/button size so the button icons are fully centered...
if ( m_titleHeightTool%2 == 0)
m_titleHeightTool++;
QString value = config.readEntry("TitleAlignment", "AlignLeft");
if (value == "AlignLeft") m_titleAlign = Qt::AlignLeft;
else if (value == "AlignHCenter") m_titleAlign = Qt::AlignHCenter;
else if (value == "AlignRight") m_titleAlign = Qt::AlignRight;
m_coloredBorder = config.readEntry("ColoredBorder", true);
m_animateButtons = config.readEntry("AnimateButtons", true);
m_menuClose = config.readEntry("CloseOnMenuDoubleClick", true);
}
QColor PlastikHandler::getColor(KWinPlastik::ColorType type, const bool active)
{
switch (type) {
case WindowContour:
return KDecoration::options()->color(ColorTitleBar, active).dark(200);
case TitleGradient1:
return hsvRelative(KDecoration::options()->color(ColorTitleBar, active), 0,-10,+10);
break;
case TitleGradient2:
return hsvRelative(KDecoration::options()->color(ColorTitleBar, active), 0,0,-25);
break;
case TitleGradient3:
return KDecoration::options()->color(ColorTitleBar, active);
break;
case ShadeTitleLight:
return alphaBlendColors(KDecoration::options()->color(ColorTitleBar, active),
Qt::white, active?205:215);
break;
case ShadeTitleDark:
return alphaBlendColors(KDecoration::options()->color(ColorTitleBar, active),
Qt::black, active?205:215);
break;
case Border:
return KDecoration::options()->color(ColorFrame, active);
case TitleFont:
return KDecoration::options()->color(ColorFont, active);
default:
return Qt::black;
}
}
const QPixmap &PlastikHandler::pixmap(Pixmaps type, bool active, bool toolWindow)
{
if (m_pixmaps[toolWindow][active][type])
return *m_pixmaps[toolWindow][active][type];
QPixmap *pm = 0;
switch (type) {
case TitleBarTileTop:
case TitleBarTile:
{
const int titleBarTileHeight = (toolWindow ? m_titleHeightTool : m_titleHeight) + 2;
// gradient used as well in TitleBarTileTop as TitleBarTile
const int gradientHeight = 2 + titleBarTileHeight-1;
QPixmap gradient(1, gradientHeight);
QPainter painter(&gradient);
QPixmap tempPixmap( 1, 4 );
KPixmapEffect::gradient(tempPixmap,
getColor(TitleGradient1, active),
getColor(TitleGradient2, active),
KPixmapEffect::VerticalGradient);
painter.drawPixmap(0,0, tempPixmap);
tempPixmap = QPixmap(1, gradientHeight-4);
KPixmapEffect::gradient(tempPixmap,
getColor(TitleGradient2, active),
getColor(TitleGradient3, active),
KPixmapEffect::VerticalGradient);
painter.drawPixmap(0,4, tempPixmap);
painter.end();
// actual titlebar tiles
if (type == TitleBarTileTop) {
pm = new QPixmap(1, 4);
painter.begin(pm);
// contour
painter.setPen(getColor(WindowContour, active) );
painter.drawPoint(0,0);
// top highlight
painter.setPen(getColor(ShadeTitleLight, active) );
painter.drawPoint(0,1);
// gradient
painter.drawPixmap(0, 2, gradient);
painter.end();
} else {
pm = new QPixmap(1, titleBarTileHeight);
painter.begin(pm);
painter.drawPixmap(0, 0, gradient, 0,2 ,-1,-1);
if (m_coloredBorder) {
painter.setPen(getColor(TitleGradient3, active).dark(110) );
} else {
painter.setPen(getColor(TitleGradient3, active) );
}
painter.drawPoint(0,titleBarTileHeight-1);
painter.end();
}
break;
}
case TitleBarLeft:
{
const int w = m_borderSize;
const int h = 4 + (toolWindow ? m_titleHeightTool : m_titleHeight) + 2;
pm = new QPixmap(w, h);
QPainter painter(pm);
painter.drawTiledPixmap(0,0, w, 4, pixmap(TitleBarTileTop, active, toolWindow) );
painter.drawTiledPixmap(0,4, w, h-4, pixmap(TitleBarTile, active, toolWindow) );
painter.setPen(getColor(WindowContour, active) );
painter.drawLine(0,0, 0,h);
painter.drawPoint(1,1);
const QColor highlightTitleLeft = getColor(ShadeTitleLight, active);
painter.setPen(highlightTitleLeft);
painter.drawLine(1,2, 1,h);
if (m_coloredBorder) {
painter.setPen(getColor(TitleGradient3, active) );
painter.drawLine(2,h-1, w-1,h-1);
}
// outside the region normally masked by doShape
painter.setPen(QColor(0,0,0) );
painter.drawLine(0, 0, 1, 0 );
painter.drawPoint(0, 1);
break;
}
case TitleBarRight:
{
const int w = m_borderSize;
const int h = 4 + (toolWindow ? m_titleHeightTool : m_titleHeight) + 2;
pm = new QPixmap(w, h);
QPainter painter(pm);
painter.drawTiledPixmap(0,0, w, 4, pixmap(TitleBarTileTop, active, toolWindow) );
painter.drawTiledPixmap(0,4, w, h-4, pixmap(TitleBarTile, active, toolWindow) );
painter.setPen(getColor(WindowContour, active) );
painter.drawLine(w-1,0, w-1,h);
painter.drawPoint(w-2,1);
const QColor highlightTitleRight = getColor(ShadeTitleDark, active);
painter.setPen(highlightTitleRight);
painter.drawLine(w-2,2, w-2,h);
if (m_coloredBorder) {
painter.setPen(getColor(TitleGradient3, active) );
painter.drawLine(0,h-1, w-3,h-1);
}
// outside the region normally masked by doShape
painter.setPen(QColor(0,0,0) );
painter.drawLine(w-2, 0, w-1, 0 );
painter.drawPoint(w-1, 1);
break;
}
case BorderLeftTile:
{
const int w = m_borderSize;
pm = new QPixmap(w, 1);
QPainter painter(pm);
if (m_coloredBorder) {
painter.setPen(getColor(WindowContour, active) );
painter.drawPoint(0, 0);
painter.setPen(getColor(ShadeTitleLight, active) );
painter.drawPoint(1, 0);
if (w > 3) {
painter.setPen(getColor(TitleGradient3, active) );
painter.drawLine(2,0, w-2,0);
}
painter.setPen(getColor(TitleGradient3, active).dark(110) );
painter.drawPoint(w-1,0);
} else {
painter.setPen(getColor(WindowContour, active) );
painter.drawPoint(0, 0);
painter.setPen(
alphaBlendColors(getColor(Border, active),
getColor(ShadeTitleLight, active), 130) );
painter.drawPoint(1, 0);
painter.setPen(getColor(Border, active) );
painter.drawLine(2,0, w-1,0);
}
painter.end();
break;
}
case BorderRightTile:
{
const int w = m_borderSize;
pm = new QPixmap(w, 1);
QPainter painter(pm);
if (m_coloredBorder) {
painter.setPen(getColor(TitleGradient3, active).dark(110) );
painter.drawPoint(0,0);
if (w > 3) {
painter.setPen(getColor(TitleGradient3, active) );
painter.drawLine(1,0, w-3,0);
}
painter.setPen(getColor(ShadeTitleDark, active) );
painter.drawPoint(w-2, 0);
painter.setPen(getColor(WindowContour, active) );
painter.drawPoint(w-1, 0);
} else {
painter.setPen(getColor(Border, active) );
painter.drawLine(0,0, w-3,0);
painter.setPen(
alphaBlendColors(getColor(Border, active),
getColor(ShadeTitleDark, active), 130) );
painter.drawPoint(w-2, 0);
painter.setPen(getColor(WindowContour, active) );
painter.drawPoint(w-1, 0);
}
painter.end();
break;
}
case BorderBottomLeft:
{
const int w = m_borderSize;
const int h = m_borderSize;
pm = new QPixmap(w, h);
QPainter painter(pm);
painter.drawTiledPixmap(0,0,w,h, pixmap(BorderBottomTile, active, toolWindow) );
painter.setPen(getColor(WindowContour, active) );
painter.drawLine(0,0, 0,h);
if (m_coloredBorder) {
if (h > 3) {
painter.setPen(getColor(ShadeTitleLight, active) );
painter.drawLine(1,0, 1,h-2);
}
painter.setPen(getColor(TitleGradient3, active) );
painter.drawLine(2,0, w-1,0);
} else {
painter.setPen(
alphaBlendColors(getColor(Border, active),
getColor(ShadeTitleLight, active), 130) );
painter.drawLine(1,0, 1,h-2);
}
painter.end();
break;
}
case BorderBottomRight:
{
const int w = m_borderSize;
const int h = m_borderSize;
pm = new QPixmap(w, h);
QPainter painter(pm);
painter.drawTiledPixmap(0,0,w,h, pixmap(BorderBottomTile, active, toolWindow) );
painter.setPen(getColor(WindowContour, active) );
painter.drawLine(w-1,0, w-1,h);
if (m_coloredBorder) {
painter.setPen(getColor(ShadeTitleDark, active) );
painter.drawLine(w-2,0, w-2,h-2);
painter.setPen(getColor(TitleGradient3, active) );
painter.drawLine(0,0, w-3,0);
} else {
painter.setPen(
alphaBlendColors(getColor(Border, active),
getColor(ShadeTitleDark, active), 130) );
painter.drawLine(w-2,0, w-2,h-2);
}
painter.end();
break;
}
case BorderBottomTile:
default:
{
const int h = m_borderSize;
pm = new QPixmap(1, m_borderSize);
QPainter painter(pm);
if (m_coloredBorder) {
painter.setPen(getColor(TitleGradient3, active).dark(110) );
painter.drawPoint(0,0);
painter.setPen(getColor(TitleGradient3, active) );
painter.drawLine(0,1, 0,h-3);
painter.setPen(getColor(ShadeTitleDark, active) );
painter.drawPoint(0, h-2);
} else {
painter.setPen(getColor(Border, active) );
painter.drawLine(0,0, 0,h-3);
painter.setPen(
alphaBlendColors(getColor(Border, active),
getColor(ShadeTitleDark, active), 130) );
painter.drawPoint(0, h-2);
}
painter.setPen(getColor(WindowContour, active) );
painter.drawPoint(0, h-1);
painter.end();
break;
}
}
m_pixmaps[toolWindow][active][type] = pm;
return *pm;
}
const QBitmap &PlastikHandler::buttonBitmap(ButtonIcon type, const QSize &size, bool toolWindow)
{
int typeIndex = type;
// btn icon size...
int reduceW = 0, reduceH = 0;
if(size.width()>14) {
reduceW = static_cast<int>(2*(size.width()/3.5) );
}
else
reduceW = 6;
if(size.height()>14)
reduceH = static_cast<int>(2*(size.height()/3.5) );
else
reduceH = 6;
int w = size.width() - reduceW;
int h = size.height() - reduceH;
if (m_bitmaps[toolWindow][typeIndex] && m_bitmaps[toolWindow][typeIndex]->size()==QSize(w,h) )
return *m_bitmaps[toolWindow][typeIndex];
// no matching pixmap found, create a new one...
delete m_bitmaps[toolWindow][typeIndex];
m_bitmaps[toolWindow][typeIndex] = 0;
QBitmap bmp = IconEngine::icon(type /*icon*/, qMin(w,h) );
QBitmap *bitmap = new QBitmap(bmp);
m_bitmaps[toolWindow][typeIndex] = bitmap;
return *bitmap;
}
QList< PlastikHandler::BorderSize >
PlastikHandler::borderSizes() const
{
// the list must be sorted
return QList< BorderSize >() << BorderTiny << BorderNormal <<
BorderLarge << BorderVeryLarge << BorderHuge <<
BorderVeryHuge << BorderOversized;
}
// make the handler accessible to other classes...
static PlastikHandler *handler = 0;
PlastikHandler* Handler()
{
return handler;
}
} // KWinPlastik
//////////////////////////////////////////////////////////////////////////////
// Plugin Stuff //
//////////////////////////////////////////////////////////////////////////////
extern "C"
{
KDE_EXPORT KDecorationFactory *create_factory()
{
KWinPlastik::handler = new KWinPlastik::PlastikHandler();
return KWinPlastik::handler;
}
}

View file

@ -0,0 +1,6 @@
[Desktop Entry]
Encoding=UTF-8
Icon=
Name=Plastik
Name[x-test]=xxPlastikxx
X-KDE-Library=kwin3_plastik

125
clients/plastik/plastik.h Normal file
View file

@ -0,0 +1,125 @@
/* Plastik KWin window decoration
Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef PLASTIK_H
#define PLASTIK_H
#include <QFont>
#include <kdecoration.h>
#include <kdecorationfactory.h>
namespace KWinPlastik {
enum ColorType {
WindowContour=0,
TitleGradient1, // top
TitleGradient2,
TitleGradient3, // bottom
ShadeTitleLight,
ShadeTitleDark,
Border,
TitleFont
};
enum Pixmaps {
TitleBarTileTop=0,
TitleBarTile,
TitleBarLeft,
TitleBarRight,
BorderLeftTile,
BorderRightTile,
BorderBottomTile,
BorderBottomLeft,
BorderBottomRight,
NumPixmaps
};
enum ButtonIcon {
CloseIcon = 0,
MaxIcon,
MaxRestoreIcon,
MinIcon,
HelpIcon,
OnAllDesktopsIcon,
NotOnAllDesktopsIcon,
KeepAboveIcon,
NoKeepAboveIcon,
KeepBelowIcon,
NoKeepBelowIcon,
ShadeIcon,
UnShadeIcon,
NumButtonIcons
};
class PlastikHandler: public QObject, public KDecorationFactory
{
Q_OBJECT
public:
PlastikHandler();
~PlastikHandler();
virtual bool reset( unsigned long changed );
virtual KDecoration* createDecoration( KDecorationBridge* );
virtual bool supports( Ability ability );
const QPixmap &pixmap(Pixmaps type, bool active, bool toolWindow);
const QBitmap &buttonBitmap(ButtonIcon type, const QSize &size, bool toolWindow);
int titleHeight() { return m_titleHeight; }
int titleHeightTool() { return m_titleHeightTool; }
const QFont &titleFont() { return m_titleFont; }
const QFont &titleFontTool() { return m_titleFontTool; }
bool titleShadow() { return m_titleShadow; }
int borderSize() { return m_borderSize; }
bool animateButtons() { return m_animateButtons; }
bool menuClose() { return m_menuClose; }
Qt::AlignmentFlag titleAlign() { return m_titleAlign; }
bool reverseLayout() { return m_reverse; }
QColor getColor(KWinPlastik::ColorType type, const bool active = true);
QList< PlastikHandler::BorderSize > borderSizes() const;
private:
void readConfig();
bool m_coloredBorder;
bool m_titleShadow;
bool m_animateButtons;
bool m_menuClose;
bool m_reverse;
int m_borderSize;
int m_titleHeight;
int m_titleHeightTool;
QFont m_titleFont;
QFont m_titleFontTool;
Qt::AlignmentFlag m_titleAlign;
// pixmap cache
QPixmap *m_pixmaps[2][2][NumPixmaps]; // button pixmaps have normal+pressed state...
QBitmap *m_bitmaps[2][NumButtonIcons];
};
PlastikHandler* Handler();
} // KWinPlastik
#endif // PLASTIK_H

View file

@ -0,0 +1,637 @@
/* Plastik KWin window decoration
Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
// #include <kwin/options.h>
#include <QAbstractButton>
#include <QStyle>
#include <QBitmap>
#include <QPainter>
#include <QPixmap>
#include <kpixmapeffect.h>
#include <QPixmap>
#include <QTimer>
#include "plastikbutton.h"
#include "plastikbutton.moc"
#include "plastikclient.h"
#include "misc.h"
namespace KWinPlastik
{
static const uint TIMERINTERVAL = 50; // msec
static const uint ANIMATIONSTEPS = 4;
PlastikButton::PlastikButton(ButtonType type, PlastikClient *parent)
: KCommonDecorationButton(type, parent),
m_client(parent),
m_iconType(NumButtonIcons),
hover(false)
{
setAttribute(Qt::WA_NoSystemBackground);
// no need to reset here as the button will be reseted on first resize.
animTmr = new QTimer(this);
animTmr->setSingleShot(true); // single-shot
connect(animTmr, SIGNAL(timeout() ), this, SLOT(animate() ) );
animProgress = 0;
}
PlastikButton::~PlastikButton()
{
}
void PlastikButton::reset(unsigned long changed)
{
if (changed&DecorationReset || changed&ManualReset || changed&SizeChange || changed&StateChange) {
switch (type() ) {
case CloseButton:
m_iconType = CloseIcon;
break;
case HelpButton:
m_iconType = HelpIcon;
break;
case MinButton:
m_iconType = MinIcon;
break;
case MaxButton:
if (isChecked()) {
m_iconType = MaxRestoreIcon;
} else {
m_iconType = MaxIcon;
}
break;
case OnAllDesktopsButton:
if (isChecked()) {
m_iconType = NotOnAllDesktopsIcon;
} else {
m_iconType = OnAllDesktopsIcon;
}
break;
case ShadeButton:
if (isChecked()) {
m_iconType = UnShadeIcon;
} else {
m_iconType = ShadeIcon;
}
break;
case AboveButton:
if (isChecked()) {
m_iconType = NoKeepAboveIcon;
} else {
m_iconType = KeepAboveIcon;
}
break;
case BelowButton:
if (isChecked()) {
m_iconType = NoKeepBelowIcon;
} else {
m_iconType = KeepBelowIcon;
}
break;
default:
m_iconType = NumButtonIcons; // empty...
break;
}
this->update();
}
}
void PlastikButton::animate()
{
animTmr->stop();
if(hover) {
if(animProgress < ANIMATIONSTEPS) {
if (Handler()->animateButtons() ) {
animProgress++;
} else {
animProgress = ANIMATIONSTEPS;
}
animTmr->start(TIMERINTERVAL); // single-shot timer
}
} else {
if(animProgress > 0) {
if (Handler()->animateButtons() ) {
animProgress--;
} else {
animProgress = 0;
}
animTmr->start(TIMERINTERVAL); // single-shot timer
}
}
repaint();
}
void PlastikButton::enterEvent(QEvent *e)
{
QAbstractButton::enterEvent(e);
hover = true;
animate();
}
void PlastikButton::leaveEvent(QEvent *e)
{
QAbstractButton::leaveEvent(e);
hover = false;
animate();
}
void PlastikButton::paintEvent(QPaintEvent *)
{
QPainter p(this);
drawButton(&p);
}
void PlastikButton::drawButton(QPainter *painter)
{
QRect r(0,0,width(),height());
bool active = m_client->isActive();
QPixmap tempPixmap;
QColor highlightColor;
if(type() == CloseButton) {
highlightColor = QColor(255,64,0);
} else {
highlightColor = Qt::white;
}
QColor contourTop = alphaBlendColors(Handler()->getColor(TitleGradient2, active),
Qt::black, 215);
QColor contourBottom = alphaBlendColors(Handler()->getColor(TitleGradient3, active),
Qt::black, 215);
QColor sourfaceTop = alphaBlendColors(Handler()->getColor(TitleGradient2, active),
Qt::white, 210);
QColor sourfaceBottom = alphaBlendColors(Handler()->getColor(TitleGradient3, active),
Qt::white, 210);
int highlightAlpha = static_cast<int>(255-((60/static_cast<double>(ANIMATIONSTEPS))*
static_cast<double>(animProgress) ) );
contourTop = alphaBlendColors(contourTop, highlightColor, highlightAlpha );
contourBottom = alphaBlendColors(contourBottom, highlightColor, highlightAlpha);
sourfaceTop = alphaBlendColors(sourfaceTop, highlightColor, highlightAlpha);
sourfaceBottom = alphaBlendColors(sourfaceBottom, highlightColor, highlightAlpha);
if (isDown() ) {
contourTop = alphaBlendColors(contourTop, Qt::black, 200);
contourBottom = alphaBlendColors(contourBottom, Qt::black, 200);
sourfaceTop = alphaBlendColors(sourfaceTop, Qt::black, 200);
sourfaceBottom = alphaBlendColors(sourfaceBottom, Qt::black, 200);
}
QPixmap buffer(width(), height());
QPainter bP(&buffer);
// fake the titlebar background
bP.drawTiledPixmap(0, 0, width(), width(), m_client->getTitleBarTile(active) );
if (type() != MenuButton || hover || animProgress != 0) {
// contour
bP.setPen(contourTop);
bP.drawLine(r.x()+2, r.y(), r.right()-2, r.y() );
bP.drawPoint(r.x()+1, r.y()+1);
bP.drawPoint(r.right()-1, r.y()+1);
bP.setPen(contourBottom);
bP.drawLine(r.x()+2, r.bottom(), r.right()-2, r.bottom() );
bP.drawPoint(r.x()+1, r.bottom()-1);
bP.drawPoint(r.right()-1, r.bottom()-1);
// sides of the contour
tempPixmap = QPixmap( 1, r.height()-2*2 );
KPixmapEffect::gradient(tempPixmap,
contourTop,
contourBottom,
KPixmapEffect::VerticalGradient);
bP.drawPixmap(r.x(), r.y()+2, tempPixmap);
bP.drawPixmap(r.right(), r.y()+2, tempPixmap);
// sort of anti-alias for the contour
bP.setPen(alphaBlendColors(Handler()->getColor(TitleGradient2, active),
contourTop, 150) );
bP.drawPoint(r.x()+1, r.y());
bP.drawPoint(r.right()-1, r.y());
bP.drawPoint(r.x(), r.y()+1);
bP.drawPoint(r.right(), r.y()+1);
bP.setPen(alphaBlendColors(Handler()->getColor(TitleGradient3, active),
contourBottom, 150) );
bP.drawPoint(r.x()+1, r.bottom());
bP.drawPoint(r.right()-1, r.bottom());
bP.drawPoint(r.x(), r.bottom()-1);
bP.drawPoint(r.right(), r.bottom()-1);
// sourface
// fill top and bottom
bP.setPen(sourfaceTop);
bP.drawLine(r.x()+2, r.y()+1, r.right()-2, r.y()+1 );
bP.setPen(sourfaceBottom);
bP.drawLine(r.x()+2, r.bottom()-1, r.right()-2, r.bottom()-1 );
// fill the rest! :)
tempPixmap = QPixmap(1, r.height()-2*2);
KPixmapEffect::gradient(tempPixmap,
sourfaceTop,
sourfaceBottom,
KPixmapEffect::VerticalGradient);
bP.drawTiledPixmap(r.x()+1, r.y()+2, r.width()-2, r.height()-4, tempPixmap);
}
if (type() == MenuButton)
{
QPixmap menuIcon(m_client->icon().pixmap( style()->pixelMetric( QStyle::PM_SmallIconSize ) ));
if (width() < menuIcon.width() || height() < menuIcon.height() ) {
menuIcon = menuIcon.scaled(width(), height());
}
bP.drawPixmap((width()-menuIcon.width())/2, (height()-menuIcon.height())/2, menuIcon);
}
else
{
int dX,dY;
const QBitmap &icon = Handler()->buttonBitmap(m_iconType, size(), decoration()->isToolWindow() );
dX = r.x()+(r.width()-icon.width())/2;
dY = r.y()+(r.height()-icon.height())/2;
if (isDown() ) {
dY++;
}
if(!isDown() && Handler()->titleShadow() ) {
QColor shadowColor;
if (qGray(Handler()->getColor(TitleFont,active).rgb()) < 100)
shadowColor = QColor(255, 255, 255);
else
shadowColor = QColor(0,0,0);
bP.setPen(alphaBlendColors(sourfaceTop, shadowColor, 180) );
bP.drawPixmap(dX+1, dY+1, icon);
}
bP.setPen(Handler()->getColor(TitleFont,active) );
bP.drawPixmap(dX, dY, icon);
}
bP.end();
painter->drawPixmap(0, 0, buffer);
}
QBitmap IconEngine::icon(ButtonIcon icon, int size)
{
if (size%2 == 0)
--size;
QBitmap bitmap(size,size);
bitmap.fill(Qt::color0);
QPainter p(&bitmap);
p.setPen(Qt::color1);
QRect r = bitmap.rect();
// line widths
int lwTitleBar = 1;
if (r.width() > 16) {
lwTitleBar = 4;
} else if (r.width() > 4) {
lwTitleBar = 2;
}
int lwArrow = 1;
if (r.width() > 16) {
lwArrow = 4;
} else if (r.width() > 7) {
lwArrow = 2;
}
switch(icon) {
case CloseIcon:
{
int lineWidth = 1;
if (r.width() > 16) {
lineWidth = 3;
} else if (r.width() > 4) {
lineWidth = 2;
}
drawObject(p, DiagonalLine, r.x(), r.y(), r.width(), lineWidth);
drawObject(p, CrossDiagonalLine, r.x(), r.bottom(), r.width(), lineWidth);
break;
}
case MaxIcon:
{
int lineWidth2 = 1; // frame
if (r.width() > 16) {
lineWidth2 = 2;
} else if (r.width() > 4) {
lineWidth2 = 1;
}
drawObject(p, HorizontalLine, r.x(), r.top(), r.width(), lwTitleBar);
drawObject(p, HorizontalLine, r.x(), r.bottom()-(lineWidth2-1), r.width(), lineWidth2);
drawObject(p, VerticalLine, r.x(), r.top(), r.height(), lineWidth2);
drawObject(p, VerticalLine, r.right()-(lineWidth2-1), r.top(), r.height(), lineWidth2);
break;
}
case MaxRestoreIcon:
{
int lineWidth2 = 1; // frame
if (r.width() > 16) {
lineWidth2 = 2;
} else if (r.width() > 4) {
lineWidth2 = 1;
}
int margin1, margin2;
margin1 = margin2 = lineWidth2*2;
if (r.width() < 8)
margin1 = 1;
// background window
drawObject(p, HorizontalLine, r.x()+margin1, r.top(), r.width()-margin1, lineWidth2);
drawObject(p, HorizontalLine, r.right()-margin2, r.bottom()-(lineWidth2-1)-margin1, margin2, lineWidth2);
drawObject(p, VerticalLine, r.x()+margin1, r.top(), margin2, lineWidth2);
drawObject(p, VerticalLine, r.right()-(lineWidth2-1), r.top(), r.height()-margin1, lineWidth2);
// foreground window
drawObject(p, HorizontalLine, r.x(), r.top()+margin2, r.width()-margin2, lwTitleBar);
drawObject(p, HorizontalLine, r.x(), r.bottom()-(lineWidth2-1), r.width()-margin2, lineWidth2);
drawObject(p, VerticalLine, r.x(), r.top()+margin2, r.height(), lineWidth2);
drawObject(p, VerticalLine, r.right()-(lineWidth2-1)-margin2, r.top()+margin2, r.height(), lineWidth2);
break;
}
case MinIcon:
{
drawObject(p, HorizontalLine, r.x(), r.bottom()-(lwTitleBar-1), r.width(), lwTitleBar);
break;
}
case HelpIcon:
{
int center = r.x()+r.width()/2 -1;
int side = r.width()/4;
// paint a question mark... code is quite messy, to be cleaned up later...! :o
if (r.width() > 16) {
int lineWidth = 3;
// top bar
drawObject(p, HorizontalLine, center-side+3, r.y(), 2*side-3-1, lineWidth);
// top bar rounding
drawObject(p, CrossDiagonalLine, center-side-1, r.y()+5, 6, lineWidth);
drawObject(p, DiagonalLine, center+side-3, r.y(), 5, lineWidth);
// right bar
drawObject(p, VerticalLine, center+side+2-lineWidth, r.y()+3, r.height()-(2*lineWidth+side+2+1), lineWidth);
// bottom bar
drawObject(p, CrossDiagonalLine, center, r.bottom()-2*lineWidth, side+2, lineWidth);
drawObject(p, HorizontalLine, center, r.bottom()-3*lineWidth+2, lineWidth, lineWidth);
// the dot
drawObject(p, HorizontalLine, center, r.bottom()-(lineWidth-1), lineWidth, lineWidth);
} else if (r.width() > 8) {
int lineWidth = 2;
// top bar
drawObject(p, HorizontalLine, center-(side-1), r.y(), 2*side-1, lineWidth);
// top bar rounding
if (r.width() > 9) {
drawObject(p, CrossDiagonalLine, center-side-1, r.y()+3, 3, lineWidth);
} else {
drawObject(p, CrossDiagonalLine, center-side-1, r.y()+2, 3, lineWidth);
}
drawObject(p, DiagonalLine, center+side-1, r.y(), 3, lineWidth);
// right bar
drawObject(p, VerticalLine, center+side+2-lineWidth, r.y()+2, r.height()-(2*lineWidth+side+1), lineWidth);
// bottom bar
drawObject(p, CrossDiagonalLine, center, r.bottom()-2*lineWidth+1, side+2, lineWidth);
// the dot
drawObject(p, HorizontalLine, center, r.bottom()-(lineWidth-1), lineWidth, lineWidth);
} else {
int lineWidth = 1;
// top bar
drawObject(p, HorizontalLine, center-(side-1), r.y(), 2*side, lineWidth);
// top bar rounding
drawObject(p, CrossDiagonalLine, center-side-1, r.y()+1, 2, lineWidth);
// right bar
drawObject(p, VerticalLine, center+side+1, r.y(), r.height()-(side+2+1), lineWidth);
// bottom bar
drawObject(p, CrossDiagonalLine, center, r.bottom()-2, side+2, lineWidth);
// the dot
drawObject(p, HorizontalLine, center, r.bottom(), 1, 1);
}
break;
}
case NotOnAllDesktopsIcon:
{
int lwMark = r.width()-lwTitleBar*2-2;
if (lwMark < 1)
lwMark = 3;
drawObject(p, HorizontalLine, r.x()+(r.width()-lwMark)/2, r.y()+(r.height()-lwMark)/2, lwMark, lwMark);
// Fall through to OnAllDesktopsIcon intended!
}
case OnAllDesktopsIcon:
{
// horizontal bars
drawObject(p, HorizontalLine, r.x()+lwTitleBar, r.y(), r.width()-2*lwTitleBar, lwTitleBar);
drawObject(p, HorizontalLine, r.x()+lwTitleBar, r.bottom()-(lwTitleBar-1), r.width()-2*lwTitleBar, lwTitleBar);
// vertical bars
drawObject(p, VerticalLine, r.x(), r.y()+lwTitleBar, r.height()-2*lwTitleBar, lwTitleBar);
drawObject(p, VerticalLine, r.right()-(lwTitleBar-1), r.y()+lwTitleBar, r.height()-2*lwTitleBar, lwTitleBar);
break;
}
case NoKeepAboveIcon:
{
int center = r.x()+r.width()/2;
// arrow
drawObject(p, CrossDiagonalLine, r.x(), center+2*lwArrow, center-r.x(), lwArrow);
drawObject(p, DiagonalLine, r.x()+center, r.y()+1+2*lwArrow, center-r.x(), lwArrow);
if (lwArrow>1)
drawObject(p, HorizontalLine, center-(lwArrow-2), r.y()+2*lwArrow, (lwArrow-2)*2, lwArrow);
// Fall through to KeepAboveIcon intended!
}
case KeepAboveIcon:
{
int center = r.x()+r.width()/2;
// arrow
drawObject(p, CrossDiagonalLine, r.x(), center, center-r.x(), lwArrow);
drawObject(p, DiagonalLine, r.x()+center, r.y()+1, center-r.x(), lwArrow);
if (lwArrow>1)
drawObject(p, HorizontalLine, center-(lwArrow-2), r.y(), (lwArrow-2)*2, lwArrow);
break;
}
case NoKeepBelowIcon:
{
int center = r.x()+r.width()/2;
// arrow
drawObject(p, DiagonalLine, r.x(), center-2*lwArrow, center-r.x(), lwArrow);
drawObject(p, CrossDiagonalLine, r.x()+center, r.bottom()-1-2*lwArrow, center-r.x(), lwArrow);
if (lwArrow>1)
drawObject(p, HorizontalLine, center-(lwArrow-2), r.bottom()-(lwArrow-1)-2*lwArrow, (lwArrow-2)*2, lwArrow);
// Fall through to KeepBelowIcon intended!
}
case KeepBelowIcon:
{
int center = r.x()+r.width()/2;
// arrow
drawObject(p, DiagonalLine, r.x(), center, center-r.x(), lwArrow);
drawObject(p, CrossDiagonalLine, r.x()+center, r.bottom()-1, center-r.x(), lwArrow);
if (lwArrow>1)
drawObject(p, HorizontalLine, center-(lwArrow-2), r.bottom()-(lwArrow-1), (lwArrow-2)*2, lwArrow);
break;
}
case ShadeIcon:
{
drawObject(p, HorizontalLine, r.x(), r.y(), r.width(), lwTitleBar);
break;
}
case UnShadeIcon:
{
int lw1 = 1;
int lw2 = 1;
if (r.width() > 16) {
lw1 = 4;
lw2 = 2;
} else if (r.width() > 7) {
lw1 = 2;
lw2 = 1;
}
int h = qMax( (r.width()/2), (lw1+2*lw2) );
// horizontal bars
drawObject(p, HorizontalLine, r.x(), r.y(), r.width(), lw1);
drawObject(p, HorizontalLine, r.x(), r.x()+h-(lw2-1), r.width(), lw2);
// vertical bars
drawObject(p, VerticalLine, r.x(), r.y(), h, lw2);
drawObject(p, VerticalLine, r.right()-(lw2-1), r.y(), h, lw2);
break;
}
default:
break;
}
p.end();
bitmap.setMask(bitmap);
return bitmap;
}
void IconEngine::drawObject(QPainter &p, Object object, int x, int y, int length, int lineWidth)
{
switch(object) {
case DiagonalLine:
if (lineWidth <= 1) {
for (int i = 0; i < length; ++i) {
p.drawPoint(x+i,y+i);
}
} else if (lineWidth <= 2) {
for (int i = 0; i < length; ++i) {
p.drawPoint(x+i,y+i);
}
for (int i = 0; i < (length-1); ++i) {
p.drawPoint(x+1+i,y+i);
p.drawPoint(x+i,y+1+i);
}
} else {
for (int i = 1; i < (length-1); ++i) {
p.drawPoint(x+i,y+i);
}
for (int i = 0; i < (length-1); ++i) {
p.drawPoint(x+1+i,y+i);
p.drawPoint(x+i,y+1+i);
}
for (int i = 0; i < (length-2); ++i) {
p.drawPoint(x+2+i,y+i);
p.drawPoint(x+i,y+2+i);
}
}
break;
case CrossDiagonalLine:
if (lineWidth <= 1) {
for (int i = 0; i < length; ++i) {
p.drawPoint(x+i,y-i);
}
} else if (lineWidth <= 2) {
for (int i = 0; i < length; ++i) {
p.drawPoint(x+i,y-i);
}
for (int i = 0; i < (length-1); ++i) {
p.drawPoint(x+1+i,y-i);
p.drawPoint(x+i,y-1-i);
}
} else {
for (int i = 1; i < (length-1); ++i) {
p.drawPoint(x+i,y-i);
}
for (int i = 0; i < (length-1); ++i) {
p.drawPoint(x+1+i,y-i);
p.drawPoint(x+i,y-1-i);
}
for (int i = 0; i < (length-2); ++i) {
p.drawPoint(x+2+i,y-i);
p.drawPoint(x+i,y-2-i);
}
}
break;
case HorizontalLine:
for (int i = 0; i < lineWidth; ++i) {
p.drawLine(x,y+i, x+length-1, y+i);
}
break;
case VerticalLine:
for (int i = 0; i < lineWidth; ++i) {
p.drawLine(x+i,y, x+i, y+length-1);
}
break;
default:
break;
}
}
} // KWinPlastik

View file

@ -0,0 +1,92 @@
/* Plastik KWin window decoration
Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef PLASTIKBUTTON_H
#define PLASTIKBUTTON_H
#include <QImage>
#include "plastik.h"
#include <kcommondecoration.h>
class QTimer;
namespace KWinPlastik {
class PlastikClient;
class PlastikButton : public KCommonDecorationButton
{
Q_OBJECT
public:
PlastikButton(ButtonType type, PlastikClient *parent);
~PlastikButton();
void reset(unsigned long changed);
PlastikClient * client() { return m_client; }
protected slots:
void animate();
protected:
void paintEvent(QPaintEvent *);
private:
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void drawButton(QPainter *painter);
private:
PlastikClient *m_client;
ButtonIcon m_iconType;
bool hover;
QTimer *animTmr;
uint animProgress;
};
/**
* This class creates bitmaps which can be used as icons on buttons. The icons
* are "hardcoded".
* Over the previous "Gimp->xpm->QImage->recolor->SmoothScale->QPixmap" solution
* it has the important advantage that icons are more scalable and at the same
* time sharp and not blurred.
*/
class IconEngine
{
public:
static QBitmap icon(ButtonIcon icon, int size);
private:
enum Object {
HorizontalLine,
VerticalLine,
DiagonalLine,
CrossDiagonalLine
};
static void drawObject(QPainter &p, Object object, int x, int y, int length, int lineWidth);
};
} // namespace KWinPlastik
#endif // PLASTIKBUTTON_H

View file

@ -0,0 +1,529 @@
/* Plastik KWin window decoration
Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <klocale.h>
#include <QBitmap>
#include <QDateTime>
#include <QFontMetrics>
#include <QImage>
#include <QLabel>
#include <QLayout>
#include <QPainter>
#include <QPixmap>
#include <qdesktopwidget.h>
#include "plastikclient.h"
#include "plastikbutton.h"
#include "misc.h"
namespace KWinPlastik
{
PlastikClient::PlastikClient(KDecorationBridge* bridge, KDecorationFactory* factory)
: KCommonDecoration (bridge, factory),
s_titleFont(QFont() )
{
memset(m_captionPixmaps, 0, sizeof(QPixmap*)*2);
}
PlastikClient::~PlastikClient()
{
clearCaptionPixmaps();
}
QString PlastikClient::visibleName() const
{
return i18n("Plastik");
}
QString PlastikClient::defaultButtonsLeft() const
{
return "M";
}
QString PlastikClient::defaultButtonsRight() const
{
return "HIAX";
}
bool PlastikClient::decorationBehaviour(DecorationBehaviour behaviour) const
{
switch (behaviour) {
case DB_MenuClose:
return Handler()->menuClose();
case DB_WindowMask:
return true;
default:
return KCommonDecoration::decorationBehaviour(behaviour);
}
}
int PlastikClient::layoutMetric(LayoutMetric lm, bool respectWindowState, const KCommonDecorationButton *btn) const
{
bool maximized = maximizeMode()==MaximizeFull && !options()->moveResizeMaximizedWindows();
switch (lm) {
case LM_BorderLeft:
case LM_BorderRight:
case LM_BorderBottom:
{
if (respectWindowState && maximized) {
return 0;
} else {
return Handler()->borderSize();
}
}
case LM_TitleEdgeTop:
{
if (respectWindowState && maximized) {
return 0;
} else {
return 4;
}
}
case LM_TitleEdgeBottom:
{
// if (respectWindowState && maximized) {
// return 1;
// } else {
return 2;
// }
}
case LM_TitleEdgeLeft:
case LM_TitleEdgeRight:
{
if (respectWindowState && maximized) {
return 0;
} else {
return 6;
}
}
case LM_TitleBorderLeft:
case LM_TitleBorderRight:
return 5;
case LM_ButtonWidth:
case LM_ButtonHeight:
case LM_TitleHeight:
{
if (respectWindowState && isToolWindow()) {
return Handler()->titleHeightTool();
} else {
return Handler()->titleHeight();
}
}
case LM_ButtonSpacing:
return 1;
case LM_ButtonMarginTop:
return 0;
case LM_ExplicitButtonSpacer:
return 3;
default:
return KCommonDecoration::layoutMetric(lm, respectWindowState, btn);
}
}
KCommonDecorationButton *PlastikClient::createButton(ButtonType type)
{
switch (type) {
case MenuButton:
return new PlastikButton(MenuButton, this);
case OnAllDesktopsButton:
return new PlastikButton(OnAllDesktopsButton, this);
case HelpButton:
return new PlastikButton(HelpButton, this);
case MinButton:
return new PlastikButton(MinButton, this);
case MaxButton:
return new PlastikButton(MaxButton, this);
case CloseButton:
return new PlastikButton(CloseButton, this);
case AboveButton:
return new PlastikButton(AboveButton, this);
case BelowButton:
return new PlastikButton(BelowButton, this);
case ShadeButton:
return new PlastikButton(ShadeButton, this);
default:
return 0;
}
}
void PlastikClient::init()
{
s_titleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();
clearCaptionPixmaps();
KCommonDecoration::init();
}
QRegion PlastikClient::cornerShape(WindowCorner corner)
{
int w = widget()->width();
int h = widget()->height();
switch (corner) {
case WC_TopLeft:
if (layoutMetric(LM_TitleEdgeLeft) > 0)
return QRegion(0, 0, 1, 2) + QRegion(1, 0, 1, 1);
else
return QRegion();
case WC_TopRight:
if (layoutMetric(LM_TitleEdgeRight) > 0)
return QRegion(w-1, 0, 1, 2) + QRegion(w-2, 0, 1, 1);
else
return QRegion();
case WC_BottomLeft:
if (layoutMetric(LM_BorderBottom) > 0)
return QRegion(0, h-1, 1, 1);
else
return QRegion();
case WC_BottomRight:
if (layoutMetric(LM_BorderBottom) > 0)
return QRegion(w-1, h-1, 1, 1);
else
return QRegion();
default:
return QRegion();
}
}
void PlastikClient::paintEvent(QPaintEvent *e)
{
QRegion region = e->region();
PlastikHandler *handler = Handler();
if (oldCaption != caption() )
clearCaptionPixmaps();
bool active = isActive();
bool toolWindow = isToolWindow();
QPainter painter(widget() );
// often needed coordinates
QRect r = widget()->rect();
int r_w = r.width();
// int r_h = r.height();
int r_x, r_y, r_x2, r_y2;
r.getCoords(&r_x, &r_y, &r_x2, &r_y2);
const int borderLeft = layoutMetric(LM_BorderLeft);
const int borderRight = layoutMetric(LM_BorderRight);
const int borderBottom = layoutMetric(LM_BorderBottom);
const int titleHeight = layoutMetric(LM_TitleHeight);
const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop);
const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom);
const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft);
const int titleEdgeRight = layoutMetric(LM_TitleEdgeRight);
const int borderBottomTop = r_y2-borderBottom+1;
const int borderLeftRight = r_x+borderLeft-1;
const int borderRightLeft = r_x2-borderRight+1;
const int titleEdgeBottomBottom = r_y+titleEdgeTop+titleHeight+titleEdgeBottom-1;
const int sideHeight = borderBottomTop-titleEdgeBottomBottom-1;
QRect Rtitle = QRect(r_x+titleEdgeLeft+buttonsLeftWidth(), r_y+titleEdgeTop,
r_x2-titleEdgeRight-buttonsRightWidth()-(r_x+titleEdgeLeft+buttonsLeftWidth()),
titleEdgeBottomBottom-(r_y+titleEdgeTop) );
QRect tempRect;
// topSpacer
if(titleEdgeTop > 0)
{
tempRect.setRect(r_x+2, r_y, r_w-2*2, titleEdgeTop );
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTileTop, active, toolWindow) );
}
}
// leftTitleSpacer
int titleMarginLeft = 0;
int titleMarginRight = 0;
if(titleEdgeLeft > 0)
{
tempRect.setRect(r_x, r_y, borderLeft, titleEdgeTop+titleHeight+titleEdgeBottom);
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarLeft, active, toolWindow) );
titleMarginLeft = borderLeft;
}
}
// rightTitleSpacer
if(titleEdgeRight > 0)
{
tempRect.setRect(borderRightLeft, r_y, borderRight, titleEdgeTop+titleHeight+titleEdgeBottom);
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarRight, active, toolWindow) );
titleMarginRight = borderRight;
}
}
// titleSpacer
const QPixmap &caption = captionPixmap();
if(Rtitle.width() > 0)
{
m_captionRect = captionRect(); // also update m_captionRect!
if (m_captionRect.isValid() && region.contains(m_captionRect) )
{
painter.drawTiledPixmap(m_captionRect, caption);
}
// left to the title
tempRect.setRect(r_x+titleMarginLeft, m_captionRect.top(),
m_captionRect.left() - (r_x+titleMarginLeft), m_captionRect.height() );
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTile, active, toolWindow) );
}
// right to the title
tempRect.setRect(m_captionRect.right()+1, m_captionRect.top(),
(r_x2-titleMarginRight) - m_captionRect.right(), m_captionRect.height() );
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(TitleBarTile, active, toolWindow) );
}
}
// leftSpacer
if(borderLeft > 0 && sideHeight > 0)
{
tempRect.setCoords(r_x, titleEdgeBottomBottom+1, borderLeftRight, borderBottomTop-1);
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderLeftTile, active, toolWindow) );
}
}
// rightSpacer
if(borderRight > 0 && sideHeight > 0)
{
tempRect.setCoords(borderRightLeft, titleEdgeBottomBottom+1, r_x2, borderBottomTop-1);
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderRightTile, active, toolWindow) );
}
}
// bottomSpacer
if(borderBottom > 0)
{
int l = r_x;
int r = r_x2;
tempRect.setRect(r_x, borderBottomTop, borderLeft, borderBottom);
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomLeft, active, toolWindow) );
l = tempRect.right()+1;
}
tempRect.setRect(borderRightLeft, borderBottomTop, borderLeft, borderBottom);
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomRight, active, toolWindow) );
r = tempRect.left()-1;
}
tempRect.setCoords(l, borderBottomTop, r, r_y2);
if (tempRect.isValid() && region.contains(tempRect) ) {
painter.drawTiledPixmap(tempRect, handler->pixmap(BorderBottomTile, active, toolWindow) );
}
}
}
QRect PlastikClient::captionRect() const
{
const QPixmap &caption = captionPixmap();
QRect r = widget()->rect();
const int titleHeight = layoutMetric(LM_TitleHeight);
const int titleEdgeBottom = layoutMetric(LM_TitleEdgeBottom);
const int titleEdgeTop = layoutMetric(LM_TitleEdgeTop);
const int titleEdgeLeft = layoutMetric(LM_TitleEdgeLeft);
const int marginLeft = layoutMetric(LM_TitleBorderLeft);
const int marginRight = layoutMetric(LM_TitleBorderRight);
const int titleLeft = r.left() + titleEdgeLeft + buttonsLeftWidth() + marginLeft;
const int titleWidth = r.width() -
titleEdgeLeft - layoutMetric(LM_TitleEdgeRight) -
buttonsLeftWidth() - buttonsRightWidth() -
marginLeft - marginRight;
Qt::AlignmentFlag a = Handler()->titleAlign();
int tX, tW; // position/width of the title buffer
if (caption.width() > titleWidth) {
tW = titleWidth;
} else {
tW = caption.width();
}
if (a == Qt::AlignLeft || (caption.width() > titleWidth) ) {
// Align left
tX = titleLeft;
} else if (a == Qt::AlignHCenter) {
// Align center
tX = titleLeft+(titleWidth- caption.width() )/2;
} else {
// Align right
tX = titleLeft+titleWidth-caption.width();
}
return QRect(tX, r.top()+titleEdgeTop, tW, titleHeight+titleEdgeBottom);
}
void PlastikClient::updateCaption()
{
QRect oldCaptionRect = m_captionRect;
if (oldCaption != caption() )
clearCaptionPixmaps();
m_captionRect = PlastikClient::captionRect();
if (oldCaptionRect.isValid() && m_captionRect.isValid() )
widget()->update(oldCaptionRect|m_captionRect);
else
widget()->update();
}
void PlastikClient::reset( unsigned long changed )
{
if (changed & SettingColors)
{
// repaint the whole thing
clearCaptionPixmaps();
widget()->update();
updateButtons();
} else if (changed & SettingFont) {
// font has changed -- update title height and font
s_titleFont = isToolWindow() ? Handler()->titleFontTool() : Handler()->titleFont();
updateLayout();
// then repaint
clearCaptionPixmaps();
widget()->update();
}
KCommonDecoration::reset(changed);
}
const QPixmap &PlastikClient::getTitleBarTile(bool active) const
{
return Handler()->pixmap(TitleBarTile, active, isToolWindow() );
}
const QPixmap &PlastikClient::captionPixmap() const
{
bool active = isActive();
if (m_captionPixmaps[active]) {
return *m_captionPixmaps[active];
}
// not found, create new pixmap...
const int maxCaptionLength = 300; // truncate captions longer than this!
QString c(caption() );
if (c.length() > maxCaptionLength) {
c.truncate(maxCaptionLength);
c.append(" [...]");
}
QFontMetrics fm(s_titleFont);
int captionWidth = fm.width(c);
int captionHeight = fm.height();
const int th = layoutMetric(LM_TitleHeight, false) + layoutMetric(LM_TitleEdgeBottom, false);
QPainter painter;
const int thickness = 2;
QPixmap *captionPixmap = new QPixmap(captionWidth+2*thickness, th);
painter.begin(captionPixmap);
painter.drawTiledPixmap(captionPixmap->rect(),
Handler()->pixmap(TitleBarTile, active, isToolWindow()) );
painter.setFont(s_titleFont);
QPoint tp(1, captionHeight-1);
if(Handler()->titleShadow())
{
QColor shadowColor;
if (qGray(Handler()->getColor(TitleFont,active).rgb()) < 100)
shadowColor = QColor(255, 255, 255);
else
shadowColor = QColor(0,0,0);
painter.setPen(alphaBlendColors(options()->color(ColorTitleBar, active), shadowColor, 205) );
painter.drawText(tp+QPoint(1,2), c);
painter.setPen(alphaBlendColors(options()->color(ColorTitleBar, active), shadowColor, 225) );
painter.drawText(tp+QPoint(2,2), c);
painter.setPen(alphaBlendColors(options()->color(ColorTitleBar, active), shadowColor, 165) );
painter.drawText(tp+QPoint(1,1), c);
}
painter.setPen(Handler()->getColor(TitleFont,active) );
painter.drawText(tp, c );
painter.end();
m_captionPixmaps[active] = captionPixmap;
return *captionPixmap;
}
void PlastikClient::clearCaptionPixmaps()
{
for (int i = 0; i < 2; ++i) {
delete m_captionPixmaps[i];
m_captionPixmaps[i] = 0;
}
oldCaption = caption();
}
} // KWinPlastik

View file

@ -0,0 +1,73 @@
/* Plastik KWin window decoration
Copyright (C) 2003-2005 Sandro Giessl <sandro@giessl.com>
based on the window decoration "Web":
Copyright (C) 2001 Rik Hemsley (rikkus) <rik@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef PLASTIKCLIENT_H
#define PLASTIKCLIENT_H
#include <kcommondecoration.h>
#include "plastik.h"
namespace KWinPlastik {
class PlastikButton;
class PlastikClient : public KCommonDecoration
{
public:
PlastikClient(KDecorationBridge* bridge, KDecorationFactory* factory);
~PlastikClient();
virtual QString visibleName() const;
virtual QString defaultButtonsLeft() const;
virtual QString defaultButtonsRight() const;
virtual bool decorationBehaviour(DecorationBehaviour behaviour) const;
virtual int layoutMetric(LayoutMetric lm, bool respectWindowState = true, const KCommonDecorationButton * = 0) const;
virtual QRegion cornerShape(WindowCorner corner);
virtual KCommonDecorationButton *createButton(ButtonType type);
virtual void init();
virtual void reset( unsigned long changed );
virtual void paintEvent(QPaintEvent *e);
virtual void updateCaption();
const QPixmap &getTitleBarTile(bool active) const;
private:
QRect captionRect() const;
const QPixmap &captionPixmap() const;
void clearCaptionPixmaps();
mutable QPixmap *m_captionPixmaps[2];
QRect m_captionRect;
QString oldCaption;
// settings...
QFont s_titleFont;
};
} // KWinPlastik
#endif // PLASTIKCLIENT_H

View file

@ -0,0 +1,26 @@
add_subdirectory( config )
########### next target ###############
set(kwin3_quartz_PART_SRCS quartz.cpp )
kde4_automoc(kwin3_quartz ${kwin3_quartz_PART_SRCS})
kde4_add_plugin(kwin3_quartz ${kwin3_quartz_PART_SRCS})
target_link_libraries(kwin3_quartz ${KDE4_KDEUI_LIBS} kdecorations kdefx)
install(TARGETS kwin3_quartz DESTINATION ${PLUGIN_INSTALL_DIR} )
########### install files ###############
install( FILES quartz.desktop DESTINATION ${DATA_INSTALL_DIR}/kwin/ )

Some files were not shown because too many files have changed in this diff Show more