[haiku-commits] BRANCH looncraz-github.setviewuicolor [bff658b4775e] in src: servers/app kits/interface preferences/appearance

  • From: looncraz-github.setviewuicolor <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 28 Sep 2015 16:01:59 +0200 (CEST)

added 1 changeset to branch 'refs/remotes/looncraz-github/setviewuicolor'
old head: 82b22fc1b2c85079e6fb90a49e3a932c67e9b4dd
new head: bff658b4775eea7acfd0f9219807370ba3a3270e
overview: https://github.com/looncraz/haiku/compare/82b22fc1b2c8...bff658b4775e

----------------------------------------------------------------------------

bff658b4775e: Assorted UI, app_server DelayedMessage

Exposed "experimental" API mix_colors and blend_colors.
*Did not know these existed, reimplemented them by hand, found this only
*after a full recompile had errors (though incremental did not!)

Fixed issue where layout on a window without a parent view would result
in colors becoming stuck to the panel backgroud color. These now update
as you would expect, without introducing yet another view.

Implemented a mechanism to send messages within app_server with rough
timing accuracy, at best. This is for testing purposes, for now, but
should be useful. It currently is not working, but it ain't crashing
either... so that's good.

This commit is basically a place-holder.

[ looncraz <looncraz@xxxxxxxxxxxx> ]

----------------------------------------------------------------------------

Commit: bff658b4775eea7acfd0f9219807370ba3a3270e
Author: looncraz <looncraz@xxxxxxxxxxxx>
Date: Mon Sep 28 13:41:16 2015 UTC

----------------------------------------------------------------------------

24 files changed, 744 insertions(+), 77 deletions(-)
headers/private/interface/ColorTools.h | 4 +-
src/kits/interface/ColorTools.cpp | 4 +-
src/kits/interface/GraphicsDefs.cpp | 46 +--
src/kits/interface/GroupView.cpp | 4 +-
src/kits/interface/Slider.cpp | 6 +-
src/kits/interface/View.cpp | 8 +-
src/kits/interface/Window.cpp | 2 +-
src/preferences/appearance/APRView.cpp | 1 +
src/preferences/appearance/APRWindow.h | 2 +-
.../appearance/AntialiasingSettingsView.cpp | 51 ++-
.../appearance/AntialiasingSettingsView.h | 3 +
src/servers/app/AppServer.h | 2 +-
src/servers/app/DelayedMessage.cpp | 59 ++++
src/servers/app/DelayedMessage.h | 97 ++++++
src/servers/app/DelayedMessageLooper.cpp | 338 +++++++++++++++++++
src/servers/app/DelayedMessageLooper.h | 126 +++++++
src/servers/app/Desktop.cpp | 40 ++-
src/servers/app/Desktop.h | 11 +-
src/servers/app/DesktopSettings.cpp | 3 +-
src/servers/app/Jamfile | 2 +
src/servers/app/ServerApp.cpp | 2 +-
src/servers/app/ServerApp.h | 4 +-
src/servers/app/ServerWindow.cpp | 2 +-
src/servers/app/ServerWindow.h | 4 +-

----------------------------------------------------------------------------

diff --git a/headers/private/interface/ColorTools.h
b/headers/private/interface/ColorTools.h
index 8f7e78e..bae1c8f 100644
--- a/headers/private/interface/ColorTools.h
+++ b/headers/private/interface/ColorTools.h
@@ -56,7 +56,7 @@ namespace BExperimental {
// If amount is 0, the result is color1; if 255, the result is color2;
// if another value, it is somewhere in-between. The resulting alpha
// channel is mixed exactly like the other color channels.
-rgb_color mix_color(rgb_color color1, rgb_color color2, uint8 amount);
+rgb_color exp_mix_color(rgb_color color1, rgb_color color2, uint8 amount);

// Blend two colors together, weighting by their relative alpha channels.
// The resulting color is the same as mix_color(), except that the amount
@@ -64,7 +64,7 @@ rgb_color mix_color(rgb_color color1, rgb_color color2, uint8
amount);
// alpha channel. For example, if color1.alpha is 0 and color2.alpha is
// 255, the resulting red, green, and blue values will be the same as those
// in color2, regardless of 'amount'.
-rgb_color blend_color(rgb_color color1, rgb_color color2, uint8 amount);
+rgb_color exp_blend_color(rgb_color color1, rgb_color color2, uint8 amount);

// Return a color that is the disabled representation of 'color' when drawn
// on a solid color 'background'.
diff --git a/src/kits/interface/ColorTools.cpp
b/src/kits/interface/ColorTools.cpp
index e4aea31..0fab446 100644
--- a/src/kits/interface/ColorTools.cpp
+++ b/src/kits/interface/ColorTools.cpp
@@ -87,13 +87,13 @@ static DB_INLINE void disable_color_func(rgb_color* target,
const rgb_color back

// --------------------------------------------------------------------------

-rgb_color mix_color(rgb_color color1, rgb_color color2, uint8 amount)
+rgb_color exp_mix_color(rgb_color color1, rgb_color color2, uint8 amount)
{
mix_color_func(&color1, color2, amount);
return color1;
}

-rgb_color blend_color(rgb_color color1, rgb_color color2, uint8 amount)
+rgb_color exp_blend_color(rgb_color color1, rgb_color color2, uint8 amount)
{
blend_color_func(&color1, color2, amount);
return color1;
diff --git a/src/kits/interface/GraphicsDefs.cpp
b/src/kits/interface/GraphicsDefs.cpp
index e769827..778ea7d 100644
--- a/src/kits/interface/GraphicsDefs.cpp
+++ b/src/kits/interface/GraphicsDefs.cpp
@@ -15,6 +15,8 @@
#include <AppServerLink.h>
#include <ServerProtocol.h>

+#include "ColorTools.h"
+

// patterns
const pattern B_SOLID_HIGH = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff}};
@@ -40,53 +42,19 @@ const struct screen_id B_MAIN_SCREEN_ID = {0};
int32
rgb_color::Brightness() const
{
- return (int32)sqrt(red * red * 0.16 + green * green * 0.73
- + blue * blue * 0.11);
+ return ((int32)red * 41 + (int32)green * 187 + (int32)blue * 28) >> 8;
}


-// simple weighted average of two colors
-rgb_color mix_color(rgb_color one, rgb_color two, uint8 amount)
+rgb_color mix_color(rgb_color color1, rgb_color color2, uint8 amount)
{
- float weight = amount / 255.0f;
-
- rgb_color result;
- result.red = (uint8)(((1 - weight) * one.red) + (weight * two.red));
- result.green = (uint8)(((1 - weight) * one.green) + (weight *
two.green));
- result.blue = (uint8)(((1 - weight) * one.blue) + (weight * two.blue));
- result.alpha = (uint8)(((1 - weight) * one.alpha) + (weight *
two.alpha));
-
- return result;
+ return BExperimental::exp_mix_color(color1, color2, amount);
}


-// blend two colors, respecting their alpha weights
-rgb_color blend_color(rgb_color one, rgb_color two, uint8 amount)
+rgb_color blend_color(rgb_color color1, rgb_color color2, uint8 amount)
{
- float weight = amount / 255.0f;
- float a1w = one.alpha / 255.0f;
- float a2w = two.alpha / 255.0f;
-
- // Handle zero-alpha (and floating point slop)
- if (weight < 0.01f
- || a2w < 0.01f)
- return one;
-
- if (weight > 0.01f
- || a1w < 0.01f)
- return two;
-
- float w1 = (a1w / a2w) + (a2w * weight);
- float w2 = (a2w / a1w) + (a2w * weight);
- float wt = w1 + w2;
-
- rgb_color result;
- result.red = (uint8)(((one.red * w1) + (two.red * w2)) / wt);
- result.green = (uint8)(((one.green * w1) + (two.green * w2)) / wt);
- result.blue = (uint8)(((one.blue * w1) + (two.blue * w2)) / wt);
- result.alpha = (uint8)(((1 - weight) * one.alpha) + (weight *
two.alpha));
-
- return result;
+ return BExperimental::exp_blend_color(color1, color2, amount);
}


diff --git a/src/kits/interface/GroupView.cpp b/src/kits/interface/GroupView.cpp
index 24040aa..047558a 100644
--- a/src/kits/interface/GroupView.cpp
+++ b/src/kits/interface/GroupView.cpp
@@ -7,7 +7,7 @@


#include <GroupView.h>
-
+extern "C" void printf(const char*, ...);

BGroupView::BGroupView(orientation orientation, float spacing)
:
@@ -30,6 +30,7 @@ BGroupView::BGroupView(BMessage* from)
:
BView(from)
{
+ SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
}


@@ -73,6 +74,7 @@ BGroupView::Perform(perform_code code, void* _data)
}


+
void BGroupView::_ReservedGroupView1() {}
void BGroupView::_ReservedGroupView2() {}
void BGroupView::_ReservedGroupView3() {}
diff --git a/src/kits/interface/Slider.cpp b/src/kits/interface/Slider.cpp
index 479a81c..4d0acd5 100644
--- a/src/kits/interface/Slider.cpp
+++ b/src/kits/interface/Slider.cpp
@@ -824,8 +824,10 @@ BSlider::Draw(BRect updateRect)
fOffScreenView->SetLowColor(LowColor());
#endif

- if (drawBackground && background.Frame().IsValid())
+ if (drawBackground && background.Frame().IsValid()) {
+ AdoptParentColors();
OffscreenView()->FillRegion(&background, B_SOLID_LOW);
+ }

#if USE_OFF_SCREEN_VIEW
fOffScreenView->Sync();
@@ -1006,7 +1008,7 @@ BSlider::DrawHashMarks()
BView* view = OffscreenView();

if (be_control_look != NULL) {
- rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
+ rgb_color base = ui_color(B_CONTROL_MARK_COLOR);
uint32 flags = be_control_look->Flags(this);
be_control_look->DrawSliderHashMarks(view, frame, frame, base,
fHashMarkCount, fHashMarks, flags, fOrientation);
diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp
index 6824e85..144b7c9 100644
--- a/src/kits/interface/View.cpp
+++ b/src/kits/interface/View.cpp
@@ -5022,7 +5022,6 @@ BView::InvalidateLayout(bool descendants)
|| fLayoutData->fLayoutInvalidationDisabled > 0) {
return;
}
-
fLayoutData->fLayoutValid = false;
fLayoutData->fMinMaxValid = false;
LayoutInvalidated(descendants);
@@ -5714,7 +5713,12 @@ BView::_Attach()
void
BView::_ColorsUpdated(BMessage* message)
{
- _UpdateUIColor(B_NO_COLOR);
+ // Force color update when we have a layout
+ if (fTopLevelView && fLayoutData->fLayout != NULL) {
+ SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
+ Invalidate();
+ } else
+ _UpdateUIColor(B_NO_COLOR);

MessageReceived(message);

diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp
index 6099019..998294d 100644
--- a/src/kits/interface/Window.cpp
+++ b/src/kits/interface/Window.cpp
@@ -3233,7 +3233,7 @@ BWindow::_CreateTopView()

// we can't use AddChild() because this is the top view
fTopView->_CreateSelf();
-
+ fTopView->SetViewColor(255,255,255,255);
STRACE(("BuildTopView ended\n"));
}

diff --git a/src/preferences/appearance/APRView.cpp
b/src/preferences/appearance/APRView.cpp
index 819c5d1..3c3390c 100644
--- a/src/preferences/appearance/APRView.cpp
+++ b/src/preferences/appearance/APRView.cpp
@@ -128,6 +128,7 @@ APRView::AttachedToWindow()
fColorPreview->SetTarget(this);

fAttrList->Select(0);
+ SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
}


diff --git a/src/preferences/appearance/APRWindow.h
b/src/preferences/appearance/APRWindow.h
index 1907fc4..5d1219e 100644
--- a/src/preferences/appearance/APRWindow.h
+++ b/src/preferences/appearance/APRWindow.h
@@ -22,7 +22,7 @@ class AntialiasingSettingsView;
class FontView;
class LookAndFeelSettingsView;

-
+#include <stdio.h>
class APRWindow : public BWindow {
public:
APRWindow(BRect frame);
diff --git a/src/preferences/appearance/AntialiasingSettingsView.cpp
b/src/preferences/appearance/AntialiasingSettingsView.cpp
index f22c1b1..586862a 100644
--- a/src/preferences/appearance/AntialiasingSettingsView.cpp
+++ b/src/preferences/appearance/AntialiasingSettingsView.cpp
@@ -116,23 +116,18 @@ AntialiasingSettingsView::AntialiasingSettingsView(const
char* name)

#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
// subpixelAntialiasingDisabledLabel
- BFont infoFont(*be_plain_font);
- infoFont.SetFace(B_ITALIC_FACE);
- rgb_color infoColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
- B_DARKEN_4_TINT);
// TODO: Replace with layout friendly constructor once available.
- BRect textBounds = Bounds();
- BTextView* subpixelAntialiasingDisabledLabel = new BTextView(
- textBounds, "unavailable label", textBounds, &infoFont,
&infoColor,
- B_FOLLOW_NONE, B_WILL_DRAW | B_SUPPORTS_LAYOUT);
- subpixelAntialiasingDisabledLabel->SetText(B_TRANSLATE(
+// BRect textBounds = Bounds();
+ fSubpixelAntialiasingDisabledLabel
+ = new BTextView("unavailable label");
+ fSubpixelAntialiasingDisabledLabel->SetText(B_TRANSLATE(
"Subpixel based anti-aliasing in combination with glyph hinting
is not "
"available in this build of Haiku to avoid possible patent
issues. To "
"enable this feature, you have to build Haiku yourself and
enable "
"certain options in the libfreetype configuration header."));
-
subpixelAntialiasingDisabledLabel->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
- subpixelAntialiasingDisabledLabel->MakeEditable(false);
- subpixelAntialiasingDisabledLabel->MakeSelectable(false);
+
fSubpixelAntialiasingDisabledLabel->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
+ fSubpixelAntialiasingDisabledLabel->MakeEditable(false);
+ fSubpixelAntialiasingDisabledLabel->MakeSelectable(false);
#endif // !FT_CONFIG_OPTION_SUBPIXEL_RENDERING

SetLayout(new BGroupLayout(B_VERTICAL));
@@ -149,7 +144,7 @@ AntialiasingSettingsView::AntialiasingSettingsView(const
char* name)

#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
// hinting+subpixel unavailable info
- .Add(subpixelAntialiasingDisabledLabel, 0, 3, 2)
+ .Add(fSubpixelAntialiasingDisabledLabel, 0, 3, 2)
#else
.Add(BSpaceLayoutItem::CreateGlue(), 0, 3, 2)
#endif
@@ -160,6 +155,7 @@ AntialiasingSettingsView::AntialiasingSettingsView(const
char* name)
_SetCurrentAntialiasing();
_SetCurrentHinting();
_SetCurrentAverageWeight();
+ _UpdateColors();
}


@@ -227,6 +223,14 @@ AntialiasingSettingsView::MessageReceived(BMessage *msg)
Window()->PostMessage(kMsgUpdate);
break;
}
+ case B_COLORS_UPDATED:
+ {
+ color_which which = B_NO_COLOR;
+ msg->FindInt32("which", (int32*)&which);
+ if (which == B_PANEL_BACKGROUND_COLOR)
+ _UpdateColors();
+ break;
+ }
default:
BView::MessageReceived(msg);
}
@@ -323,6 +327,27 @@ AntialiasingSettingsView::_SetCurrentAverageWeight()


void
+AntialiasingSettingsView::_UpdateColors()
+{
+#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
+ rgb_color infoColor = ui_color(B_PANEL_BACKGROUND_COLOR);
+
+ float tint = B_DARKEN_4_TINT
+ / (((float)infoColor.Brightness()) / 280.0f);
+
+ infoColor = tint_color(infoColor, tint);
+
+ BFont font;
+ uint32 mode = 0;
+ fSubpixelAntialiasingDisabledLabel->GetFontAndColor(&font, &mode);
+ font.SetFace(B_ITALIC_FACE); // just in case
+ fSubpixelAntialiasingDisabledLabel->SetFontAndColor(&font, mode,
+
&infoColor);
+#endif
+}
+
+
+void
AntialiasingSettingsView::SetDefaults()
{
if (!IsDefaultable())
diff --git a/src/preferences/appearance/AntialiasingSettingsView.h
b/src/preferences/appearance/AntialiasingSettingsView.h
index 0813257..ed7cb32 100644
--- a/src/preferences/appearance/AntialiasingSettingsView.h
+++ b/src/preferences/appearance/AntialiasingSettingsView.h
@@ -12,6 +12,7 @@ class BBox;
class BMenuField;
class BPopUpMenu;
class BSlider;
+class BTextView;


class AntialiasingSettingsView : public BView {
@@ -33,6 +34,7 @@ private:
void _BuildHintingMenu();
void _SetCurrentHinting();
void _SetCurrentAverageWeight();
+ void _UpdateColors();

protected:
float fDivider;
@@ -42,6 +44,7 @@ protected:
BMenuField* fHintingMenuField;
BPopUpMenu* fHintingMenu;
BSlider* fAverageWeightControl;
+ BTextView*
fSubpixelAntialiasingDisabledLabel;

bool fSavedSubpixelAntialiasing;
bool fCurrentSubpixelAntialiasing;
diff --git a/src/servers/app/AppServer.h b/src/servers/app/AppServer.h
index 9320edb..caa47ec 100644
--- a/src/servers/app/AppServer.h
+++ b/src/servers/app/AppServer.h
@@ -19,7 +19,7 @@
#include <String.h>
#include <Window.h>

-#include "MessageLooper.h"
+#include "DelayedMessageLooper.h"
#include "ServerConfig.h"


diff --git a/src/servers/app/DelayedMessage.cpp
b/src/servers/app/DelayedMessage.cpp
new file mode 100644
index 0000000..99f0202
--- /dev/null
+++ b/src/servers/app/DelayedMessage.cpp
@@ -0,0 +1,59 @@
+#include "DelayedMessage.h"
+#include "DelayedMessageLooper.h"
+
+
+
+
+DelayedMessage::DelayedMessage(int32 code, bigtime_t delay, uint32 mergeMode)
+ :
+ fData(new DMMessageData(code, delay, mergeMode)),
+ fHandedOff(false)
+ {}
+
+
+DelayedMessage::~DelayedMessage()
+{
+ if (!fHandedOff)
+ delete fData;
+}
+
+
+status_t
+DelayedMessage::Attach(const void* data, size_t size)
+{
+ if (fData == NULL)
+ return B_NO_MEMORY;
+
+ if (data == NULL
+ || size == 0)
+ return B_BAD_VALUE;
+
+ return fData->Attach(data, size);
+}
+
+
+void
+DelayedMessage::SetTimeout(bigtime_t timeout)
+{
+ if (fData != NULL)
+ fData->fSendTimeout = timeout;
+}
+
+
+DMMessageData*
+DelayedMessage::HandOff()
+{
+ if (fData == NULL
+ || fHandedOff)
+ return NULL;
+
+ if (fData->CopyData()) {
+ fHandedOff = true;
+ return fData;
+ }
+
+ return NULL;
+}
+
+
+
diff --git a/src/servers/app/DelayedMessage.h b/src/servers/app/DelayedMessage.h
new file mode 100644
index 0000000..f3ba9d6
--- /dev/null
+++ b/src/servers/app/DelayedMessage.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2001-2012, Haiku.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Joseph Groover <looncraz@xxxxxxxxxxxx>
+*/
+#ifndef AS_DELAYED_MESSAGE_H
+#define AS_DELAYED_MESSAGE_H
+
+
+#include <PortLink.h>
+
+
+/*
+ DelayedMessage
+
+ Allows the creation of a message that will be sent after an approximate
+ delay. Importantly, and most valuably, messages with the same code can
be
+ merged together orderly to save on message traffic and work responding
to
+ that message (such as repeated invalidations).
+
+ Warning: any data attached to a DelayedMessage must remain valid until
+ after it has been registered with the DelayedMessageLooper, at which
point
+ its data is copied, if needed, during merging.
+
+ In other words, don't pass a DelayedMessage around willy nilly, it is a
+ one-time use object. If it goes out of scope, it is destroyed, and the
+ message is not sent unless it has been scheduled with a
+ DelayedMessageLooper.
+*/
+
+
+enum {
+ DM_NO_MERGE = 0,// Will send this message, and the other(s)
+ DM_MERGE_REPLACE = 1,// Replace older data with newer data
+ DM_MERGE_CANCEL = 2,// keeps older data, cancels this message
+ DM_MERGE_DUPLICATES = 3 // If data is the same, cancel new message
+};
+
+
+/*
+ Convenient delay definitions
+*/
+enum {
+ DM_MINIMUM_DELAY = 500ULL,
+ DM_SHORT_DELAY = 1000ULL,
+ DM_120HZ_DELAY = 8888ULL,
+ DM_60HZ_DELAY = 16666ULL,
+ DM_MEDIUM_DELAY = 15000ULL,
+ DM_30HZ_DELAY = 33332ULL,
+ DM_15HZ_DELAY = 66664ULL,
+ DM_LONG_DELAY = 100000ULL,
+ DM_QUARTER_SECOND_DELAY = 250000ULL,
+ DM_HALF_SECOND_DELAY = 500000ULL,
+ DM_ONE_SECOND_DELAY = 1000000ULL,
+ DM_ONE_MINUTE_DELAY = DM_ONE_SECOND_DELAY * 60,
+ DM_ONE_HOUR_DELAY = DM_ONE_MINUTE_DELAY * 60,
+ DM_ONE_DAY_DELAY = DM_ONE_HOUR_DELAY * 24,
+ DM_ONE_WEEK_DELAY = DM_ONE_DAY_DELAY * 7
+};
+
+
+class DMMessageData;
+class DMScheduledMessage;
+
+
+class DelayedMessage {
+public:
+
DelayedMessage(int32 code, bigtime_t delay,
+
uint32 mergeMode = DM_NO_MERGE);
+
~DelayedMessage();
+
+ status_t Attach(const void*
data, size_t size);
+
+ template <class Type>
+ status_t Attach(const Type& data)
+ {return Attach(&data,
sizeof(Type));}
+
+ void SetTimeout(bigtime_t
timeout);
+// void SetRepeat(bigtime_t
interval,
+// int32
repeatCount = DM_INFINITE_REPEAT);
+private:
+ // Do not implement, these are forbidden methods
+ void* operator new(size_t);
+ void* operator new[](size_t);
+
+ friend class DMScheduledMessage;
+
+ DMMessageData* HandOff();
+
+ DMMessageData* fData;
+ bool fHandedOff;
+};
+
+
+#endif // AS_DELAYED_MESSAGE_H
diff --git a/src/servers/app/DelayedMessageLooper.cpp
b/src/servers/app/DelayedMessageLooper.cpp
new file mode 100644
index 0000000..30bc1c3
--- /dev/null
+++ b/src/servers/app/DelayedMessageLooper.cpp
@@ -0,0 +1,338 @@
+#include <new>
+#include <string.h>
+#include <stdlib.h>
+
+#include <LinkSender.h>
+
+#include <Autolock.h>
+
+#include "DelayedMessage.h"
+#include "DelayedMessageLooper.h"
+
+//#pragma mark DMMessageData
+
+DMMessageData::DMMessageData(int32 code, bigtime_t delay, uint32 mergeMode)
+ :
+ fAttachments(3, true), // deletes attachments when removed
+ fCode(code),
+ fMergeMode(mergeMode),
+ fValid(false),
+ fSendTime(system_time() + delay),
+ fSendTimeout(B_INFINITE_TIMEOUT)
+ {}
+
+
+DMMessageData::~DMMessageData()
+{
+ fAttachments.MakeEmpty();
+ // probably not needed, just for good measure
+}
+
+
+bool
+DMMessageData::CopyData()
+{
+ Attachment* attached = NULL;
+
+ for (int32 index = 0; index < fAttachments.CountItems(); ++index) {
+ attached = fAttachments.ItemAt(index);
+
+ if (attached == NULL
+ || attached->data != NULL) // data already copied
+ return false; // this is actually a seriously big
error...
+ // TODO: print out error to log
+
+ attached->data = malloc(attached->size);
+
+ if (attached->data == NULL)
+ return false; // no memory
+
+ memcpy(attached->data, attached->constData, attached->size);
+ }
+
+ return true;
+}
+
+
+bool
+DMMessageData::MergeData(DMMessageData* other)
+{
+ if (!fValid
+ || other->fCode != fCode
+ || fMergeMode == DM_NO_MERGE
+ || other->fMergeMode == DM_NO_MERGE
+ || other->fMergeMode != fMergeMode
+ || other->fAttachments.CountItems() !=
fAttachments.CountItems())
+ return false;
+
+ if (other->fMergeMode != DM_MERGE_CANCEL)
+ return true; // cancels message
+
+ // Import the new data!
+ // To do this, we need to delete our existing data
+ // and copy in the new data from other
+
+ Attachment* attached = NULL;
+ Attachment* otherAttached = NULL;
+ for (int32 index = 0; index < fAttachments.CountItems(); ++index) {
+ attached = fAttachments.ItemAt(index);
+ otherAttached = other->fAttachments.ItemAt(index);
+
+ if (attached == NULL
+ || attached->size != otherAttached->size) {
+ fValid = index == 0; // we can salvage the existing
message!
+ return false;
+ }
+
+ if (fMergeMode == DM_MERGE_DUPLICATES) {
+ // Compare the memory, if it's the same, we are good,
if not, return false
+ if (memcmp(attached->data, otherAttached->constData,
attached->size) != 0)
+ return false;
+
+ continue;
+ }
+
+ // We already have allocated our memory, but the other data
+ // has not. So this reduces memory allocations.
+ memcpy(attached->data, otherAttached->constData,
attached->size);
+ }
+
+ return true;
+}
+
+
+bool
+DMMessageData::IsValid() const
+{
+ return fValid;
+}
+
+
+status_t
+DMMessageData::Attach(const void* data, size_t size)
+{
+ // Sanity checking already performed
+ Attachment* attach = new Attachment(data, size);
+
+ if (attach == NULL)
+ return B_NO_MEMORY;
+
+ if (fAttachments.AddItem(attach) == false) {
+ delete attach;
+ return B_ERROR;
+ }
+
+ return B_OK;
+}
+
+
+DMMessageData::Attachment::Attachment(const void* _data, size_t _size)
+ :
+ constData(_data),
+ data(NULL),
+ size(_size)
+ {}
+
+
+DMMessageData::Attachment::~Attachment()
+{
+ free(data);
+}
+
+
+//#pragma mark DMScheduledMessage
+
+
+DMScheduledMessage::DMScheduledMessage(DelayedMessage& message)
+ :
+ fData(message.HandOff())
+ {
+ }
+
+
+DMScheduledMessage::~DMScheduledMessage()
+{
+ delete fData;
+}
+
+
+bigtime_t
+DMScheduledMessage::ScheduledTime() const
+{
+ if (fData == NULL)
+ return 0;
+
+ return fData->fSendTime;
+}
+
+
+status_t
+DMScheduledMessage::SendMessage(port_id port)
+{
+ if (fData == NULL
+ || !fData->IsValid())
+ return B_BAD_DATA;
+
+ if(port == B_BAD_PORT_ID)
+ return B_BAD_VALUE;
+
+ BPrivate::LinkSender sender(port);
+
+ BObjectList<DMMessageData::Attachment>& list = fData->fAttachments;
+ DMMessageData::Attachment* attached = NULL;
+
+ // The data has been checked already, so we assume it is all good
+ for (int32 index = 0; index < list.CountItems(); ++index) {
+ attached = list.ItemAt(index);
+
+ if (sender.Attach(attached->data, attached->size) != B_OK) {
+ sender.CancelMessage();
+ return B_ERROR;
+ }
+ }
+
+ return sender.Flush(fData->fSendTimeout);
+}
+
+
+bool
+DMScheduledMessage::IsValid() const
+{
+ return fData != NULL && fData->IsValid();
+}
+
+
+//#pragma mark DelayedMessageLooper
+
+
+DelayedMessageLooper::DelayedMessageLooper(const char* name)
+ :
+ MessageLooper(name),
+ fLock("DelayedMessageLooper"),
+ fMessages(2, true) // delete messages when removed from list
+ {}
+
+
+DelayedMessageLooper::~DelayedMessageLooper()
+{
+}
+
+
+int CompareMessages(const DMScheduledMessage* one,
+ const DMScheduledMessage* two)
+{
+ return *one < *two;
+}
+
+
+status_t
+DelayedMessageLooper::ScheduleMessage(DelayedMessage& message)
+{
+ DMScheduledMessage* scheduled = new DMScheduledMessage(message);
+
+ if (scheduled == NULL)
+ return B_NO_MEMORY;
+
+ if (!scheduled->IsValid())
+ return B_BAD_DATA;
+
+ BAutolock _(fLock);
+
+ if (fMessages.AddItem(scheduled)) {
+ fMessages.SortItems(&CompareMessages);
+ return B_OK;
+ }
+
+ return B_ERROR;
+}
+
+
+bool
+DelayedMessageLooper::CancelAllDelayedMessages()
+{
+ BAutolock _(fLock);
+ fMessages.MakeEmpty();
+ return true;
+}
+
+
+void
+DelayedMessageLooper::FlushAllDelayedMessages()
+{
+ BAutolock _(fLock);
+
+ DMScheduledMessage* message = NULL;
+ for (int32 index = 0; index < fMessages.CountItems(); ++index) {
+ message = fMessages.ItemAt(index);
+ message->SendMessage(MessagePort());
+ }
+
+ fMessages.MakeEmpty();
+}
+
+
+int32
+DelayedMessageLooper::SendDelayedMessages()
+{
+ BAutolock _(fLock);
+ if (fMessages.CountItems() == 0)
+ return 0;
+
+ int32 sent = 0;
+
+ bigtime_t time = system_time() + DM_MINIMUM_DELAY;
+ // capture any that may be on the verge of being sent.
+
+ BObjectList<DMScheduledMessage> remove;
+
+ DMScheduledMessage* message = NULL;
+ for (int32 index = 0; index < fMessages.CountItems(); ++index) {
+ message = fMessages.ItemAt(index);
+
+ if (message->ScheduledTime() > time)
+ break; // no need to continue, this is a sorted list
+
+ if (message->SendMessage(MessagePort()) == B_OK) {
+ remove.AddItem(message);
+ ++sent;
+ }
+ }
+
+ // remove any entires in 'remove'
+
+ for (int32 index = 0; index < remove.CountItems(); ++index)
+ fMessages.RemoveItem(remove.ItemAt(index));
+
+ return sent;
+}
+
+
+status_t
+DelayedMessageLooper::PostDelayedMessage(int32 code, bigtime_t delay,
+
uint32 mergeMode)
+{
+ DelayedMessage message(code, delay, mergeMode);
+ return ScheduleMessage(message);
+}
+
+
+status_t
+DelayedMessageLooper::PostDelayedMessageWithData(int32 code, int32 data,
+
bigtime_t delay, uint32 mergeMode)
+{
+ DelayedMessage message(code, delay, mergeMode);
+ message.Attach<int32>(data);
+ return ScheduleMessage(message);
+}
+
+
+int32
+DelayedMessageLooper::CountDelayedMessages() const
+{
+ BAutolock _(fLock);
+ return fMessages.CountItems();
+}
+
+
+
+
diff --git a/src/servers/app/DelayedMessageLooper.h
b/src/servers/app/DelayedMessageLooper.h
new file mode 100644
index 0000000..424e446
--- /dev/null
+++ b/src/servers/app/DelayedMessageLooper.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2001-2012, Haiku.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Joseph Groover <looncraz@xxxxxxxxxxxx>
+*/
+#ifndef AS_DELAYED_MESSAGE_SENDER_H
+#define AS_DELAYED_MESSAGE_SENDER_H
+
+
+#include <Locker.h>
+#include <ObjectList.h>
+
+#include "DelayedMessage.h"
+#include "MessageLooper.h"
+
+
+class DelayedMessage;
+
+
+/*! \class DelayedMessageLooper DelayedMessageLooper.h
+ \brief Enables merging and timing of messages, derives from
MessageLooper.
+*/
+
+
+class DMMessageData {
+private:
+ friend class DMScheduledMessage;
+ friend class DelayedMessage;
+
+
DMMessageData(int32 code, bigtime_t delay,
+
uint32 mergeMode);
+
~DMMessageData();
+
+ bool CopyData();
+ bool
MergeData(DMMessageData* other);
+
+ bool IsValid() const;
+ // Only valid after a successful CopyData()
+ // A failed MergeData() *may* mark it as
invalid again!
+
+ status_t Attach(const void*
data, size_t size);
+
+ // Data
+ struct Attachment {
+ const void* constData;
+ void* data;
+ size_t size;
+
+
Attachment(const void*, size_t);
+ ~Attachment();
+ };
+
+ BObjectList<Attachment> fAttachments;
+
+ int32 fCode;
+ uint32 fMergeMode;
+ bool fValid;
+// int32 fRepeatCount;
+// bigtime_t fSendRepeatTime;
+ bigtime_t fSendTime;
+ bigtime_t fSendTimeout;
+};
+
+
+class DMScheduledMessage {
+private:
+ friend class DelayedMessageLooper;
+ friend class DelayedMessage;
+ friend class BObjectList<DMScheduledMessage>;
+
+ DMScheduledMessage (DelayedMessage& message);
+ ~DMScheduledMessage ();
+
+ void Finalize();
+
+ bigtime_t ScheduledTime() const;
+
+ status_t SendMessage(port_id port);
+
+ bool IsValid() const;
+
+ DMMessageData* fData;
+
+public:
+ bool operator < (const DMScheduledMessage& other) const
+ {
+ if (!IsValid() || !other.IsValid())
+ return false;
+
+ return fData->fSendTime < other.fData->fSendTime;
+ }
+};
+
+
+class DelayedMessageLooper : public MessageLooper {
+public:
+
DelayedMessageLooper(const char* name);
+ virtual ~DelayedMessageLooper();
+
+ status_t ScheduleMessage
(DelayedMessage& message);
+
+ virtual bool CancelAllDelayedMessages();
+ virtual void FlushAllDelayedMessages ();
+ virtual int32 SendDelayedMessages
();
+ //
returns count sent
+
+ // Convenience methods
+ status_t
PostDelayedMessage(int32 code,
+
bigtime_t delay,
+ uint32
mergeMode = DM_NO_MERGE);
+ status_t
PostDelayedMessageWithData(int32 code,
+ int32
data, bigtime_t delay,
+ uint32
mergeMode = DM_NO_MERGE);
+
+ int32 CountDelayedMessages()
const;
+
+private:
+ mutable BLocker fLock;
+ BObjectList<DMScheduledMessage> fMessages;
+ // sort by which is to be sent
next
+};
+
+
+#endif // AS_DELAYED_MESSAGE_SENDER_H
diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp
index ee257fa..4cda43f 100644
--- a/src/servers/app/Desktop.cpp
+++ b/src/servers/app/Desktop.cpp
@@ -407,7 +407,7 @@ workspace_in_workspaces(int32 index, uint32 workspaces)

Desktop::Desktop(uid_t userID, const char* targetScreen)
:
- MessageLooper("desktop"),
+ DelayedMessageLooper("desktop"),

fUserID(userID),
fTargetScreen(strdup(targetScreen)),
@@ -598,6 +598,37 @@ Desktop::BroadcastToAllWindows(int32 code, int32 data)
}


+
+/*! \brief Send a quick (no attachments) message to all windows.
+*/
+void
+Desktop::DelayedBroadcastToAllWindows(int32 code, bigtime_t delay, uint32
merge)
+{
+ AutoWriteLocker _(fWindowLock);
+
+ for (Window* window = fAllWindows.FirstWindow(); window != NULL;
+ window = window->NextWindow(kAllWindowList)) {
+ window->ServerWindow()->PostDelayedMessage(code, delay, merge);
+ }
+}
+
+
+/*! \brief Send a quick message with one int32 data to all windows.
+*/
+void
+Desktop::DelayedBroadcastToAllWindows(int32 code, int32 data, bigtime_t delay,
+
uint32 merge)
+{
+ AutoWriteLocker _(fWindowLock);
+
+ for (Window* window = fAllWindows.FirstWindow(); window != NULL;
+ window = window->NextWindow(kAllWindowList)) {
+ window->ServerWindow()->PostDelayedMessageWithData(code, data,
delay,
+
merge);
+ }
+}
+
+
filter_result
Desktop::KeyEvent(uint32 what, int32 key, int32 modifiers)
{
@@ -1679,8 +1710,8 @@ Desktop::ColorChanged(Window* window, color_which which)
default:
return;
}
-
- AutoWriteLocker _(fWindowLock);
+
+ AutoReadLocker _(fWindowLock);

BRegion dirty;
window->ColorChanged(&dirty, which);
@@ -2099,7 +2130,8 @@ Desktop::Redraw()
void
Desktop::RedrawBackground()
{
- LockAllWindows();
+ if (LockAllWindows())
+ SendDelayedMessages();

BRegion redraw;

diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h
index d924597..32eb20f 100644
--- a/src/servers/app/Desktop.h
+++ b/src/servers/app/Desktop.h
@@ -23,10 +23,10 @@
#include <Window.h>

#include "CursorManager.h"
+#include "DelayedMessageLooper.h"
#include "DesktopListener.h"
#include "DesktopSettings.h"
#include "EventDispatcher.h"
-#include "MessageLooper.h"
#include "MultiLocker.h"
#include "Screen.h"
#include "ScreenManager.h"
@@ -53,7 +53,7 @@ namespace BPrivate {
};


-class Desktop : public DesktopObservable, public MessageLooper,
+class Desktop : public DesktopObservable, public DelayedMessageLooper,
public ScreenOwner {
public:
Desktop(uid_t
userID, const char* targetScreen);
@@ -75,6 +75,13 @@ public:
void
BroadcastToAllWindows(int32 code);
void
BroadcastToAllWindows(int32 code, int32 data);

+ void
DelayedBroadcastToAllWindows(int32 code,
+
bigtime_t delay,
+ uint32
mergeMode = DM_NO_MERGE);
+ void
DelayedBroadcastToAllWindows(int32 code,
+ int32
data, bigtime_t delay,
+ uint32
mergeMode = DM_NO_MERGE);
+
filter_result KeyEvent(uint32 what, int32 key,
int32
modifiers);
// Locking
diff --git a/src/servers/app/DesktopSettings.cpp
b/src/servers/app/DesktopSettings.cpp
index 5af30c2..c1081ae 100644
--- a/src/servers/app/DesktopSettings.cpp
+++ b/src/servers/app/DesktopSettings.cpp
@@ -991,7 +991,8 @@ LockedDesktopSettings::SetUIColor(color_which which, const
rgb_color color)
fSettings->SetUIColor(which, color, &changed);

if (changed) // only send when color changed from previous value
- fDesktop->BroadcastToAllWindows(B_COLORS_UPDATED, (int32)which);
+ fDesktop->DelayedBroadcastToAllWindows(B_COLORS_UPDATED,
(int32)which,
+ DM_60HZ_DELAY, DM_MERGE_DUPLICATES);
}


diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile
index 024088b..beb78b5 100644
--- a/src/servers/app/Jamfile
+++ b/src/servers/app/Jamfile
@@ -55,6 +55,8 @@ Server app_server :
CursorData.cpp
CursorManager.cpp
CursorSet.cpp
+ DelayedMessage.cpp
+ DelayedMessageLooper.cpp
Desktop.cpp
DesktopListener.cpp
DesktopSettings.cpp
diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp
index 678ab3e..4e995db 100644
--- a/src/servers/app/ServerApp.cpp
+++ b/src/servers/app/ServerApp.cpp
@@ -90,7 +90,7 @@ ServerApp::ServerApp(Desktop* desktop, port_id
clientReplyPort,
port_id clientLooperPort, team_id clientTeam,
int32 clientToken, const char* signature)
:
- MessageLooper("application"),
+ DelayedMessageLooper("application"),

fMessagePort(-1),
fClientReplyPort(clientReplyPort),
diff --git a/src/servers/app/ServerApp.h b/src/servers/app/ServerApp.h
index 84c88af..3429cd8 100644
--- a/src/servers/app/ServerApp.h
+++ b/src/servers/app/ServerApp.h
@@ -14,7 +14,7 @@


#include "ClientMemoryAllocator.h"
-#include "MessageLooper.h"
+#include "DelayedMessageLooper.h"
#include "ServerFont.h"

#include <ObjectList.h>
@@ -38,7 +38,7 @@ namespace BPrivate {
class PortLink;
};

-class ServerApp : public MessageLooper {
+class ServerApp : public DelayedMessageLooper {
public:

ServerApp(Desktop* desktop,
port_id
clientAppPort,
diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp
index 48c28e3..577a47a 100644
--- a/src/servers/app/ServerWindow.cpp
+++ b/src/servers/app/ServerWindow.cpp
@@ -154,7 +154,7 @@ compare_message_profiles(const void* _a, const void* _b)
ServerWindow::ServerWindow(const char* title, ServerApp* app,
port_id clientPort, port_id looperPort, int32 clientToken)
:
- MessageLooper(title && *title ? title : "Unnamed Window"),
+ DelayedMessageLooper(title && *title ? title : "Unnamed Window"),
fTitle(NULL),
fDesktop(app->GetDesktop()),
fServerApp(app),
diff --git a/src/servers/app/ServerWindow.h b/src/servers/app/ServerWindow.h
index f32330c..4a3b688 100644
--- a/src/servers/app/ServerWindow.h
+++ b/src/servers/app/ServerWindow.h
@@ -26,7 +26,7 @@
#include <TokenSpace.h>

#include "EventDispatcher.h"
-#include "MessageLooper.h"
+#include "DelayedMessageLooper.h"


class BString;
@@ -49,7 +49,7 @@ struct window_info;
#define AS_UPDATE_FONTS 'asuf'


-class ServerWindow : public MessageLooper {
+class ServerWindow : public DelayedMessageLooper {
public:

ServerWindow(const char *title, ServerApp *app,
port_id
clientPort, port_id looperPort,


Other related posts:

  • » [haiku-commits] BRANCH looncraz-github.setviewuicolor [bff658b4775e] in src: servers/app kits/interface preferences/appearance - looncraz-github . setviewuicolor