Move ekiga to desktop directory
[unleashed-userland.git] / components / desktop / ekiga / patches / ekiga-06-t140.patch
blobae147e0f4d6e0630d38c98e16da0437020b1daf8
1 diff --git a/ekiga.schemas.in.in b/ekiga.schemas.in.in
2 index 822270f..4eb5b28 100644
3 --- a/ekiga.schemas.in.in
4 +++ b/ekiga.schemas.in.in
5 @@ -991,5 +991,38 @@
6 <long>Automatically reject or forward incoming calls if no answer is given after the specified amount of time (in seconds)</long>
7 </locale>
8 </schema>
9 + <schema>
10 + <key>/schemas/apps/@PACKAGE_NAME@/protocols/t140/enable_realtime</key>
11 + <applyto>/apps/@PACKAGE_NAME@/protocols/t140/enable_realtime</applyto>
12 + <owner>Ekiga</owner>
13 + <type>bool</type>
14 + <default>true</default>
15 + <locale name="C">
16 + <short>Enable Realtime</short>
17 + <long>Enable Realtime</long>
18 + </locale>
19 + </schema>
20 + <schema>
21 + <key>/schemas/apps/@PACKAGE_NAME@/protocols/t140/buffer_time</key>
22 + <applyto>/apps/@PACKAGE_NAME@/protocols/t140/buffer_time</applyto>
23 + <owner>Ekiga</owner>
24 + <type>int</type>
25 + <default>300</default>
26 + <locale name="C">
27 + <short>Buffer time</short>
28 + <long>Buffer time (in ms)</long>
29 + </locale>
30 + </schema>
31 + <schema>
32 + <key>/schemas/apps/@PACKAGE_NAME@/protocols/t140/character_per_second</key>
33 + <applyto>/apps/@PACKAGE_NAME@/protocols/t140/character_per_second</applyto>
34 + <owner>Ekiga</owner>
35 + <type>int</type>
36 + <default>30</default>
37 + <locale name="C">
38 + <short>Character per Second</short>
39 + <long>Character per Second</long>
40 + </locale>
41 + </schema>
42 </schemalist>
43 </gconfschemafile>
44 diff --git a/lib/engine/chat/chat.h b/lib/engine/chat/chat.h
45 index 94e8de8..5fd2aae 100644
46 --- a/lib/engine/chat/chat.h
47 +++ b/lib/engine/chat/chat.h
48 @@ -58,7 +58,8 @@ namespace Ekiga
51 virtual void message (const std::string to,
52 - const std::string msg) = 0;
53 + const std::string msg,
54 + bool flag) = 0;
56 /** Tell the observer about a new service message, like :
57 * observer.notice ("Snark just disconnected");
58 @@ -109,6 +110,8 @@ namespace Ekiga
59 * @return True if it was valid to send a message
61 virtual bool send_message (const std::string msg) = 0;
63 + virtual void display_message (const std::string msg) = 0;
65 /** This signal is emitted when the Chat has been updated.
67 @@ -130,6 +133,12 @@ namespace Ekiga
68 /** This chain allows the Chat to present forms to the user.
70 ChainOfResponsibility<FormRequest*> questions;
72 + /** True if the chat is enabled real-time text.
73 + */
74 + virtual bool is_real_time_text_enabled () = 0;
76 + virtual int real_time_buffering_time () { return 300; }
80 diff --git a/lib/engine/components/echo/echo-simple.cpp b/lib/engine/components/echo/echo-simple.cpp
81 index 6e3789b..1b41dc3 100644
82 --- a/lib/engine/components/echo/echo-simple.cpp
83 +++ b/lib/engine/components/echo/echo-simple.cpp
84 @@ -83,11 +83,20 @@ Echo::SimpleChat::send_message (const std::string msg)
85 for (std::list<gmref_ptr<Ekiga::ChatObserver> >::iterator iter = observers.begin ();
86 iter != observers.end ();
87 ++iter)
88 - (*iter)->message ("Echo", msg);
89 + (*iter)->message ("Echo", msg, false);
91 return true;
94 +void
95 +Echo::SimpleChat::display_message (const std::string msg)
97 + for (std::list<gmref_ptr<Ekiga::ChatObserver> >::iterator iter = observers.begin ();
98 + iter != observers.end ();
99 + ++iter)
100 + (*iter)->message ("Echo", msg, false);
103 const std::string
104 Echo::SimpleChat::get_title() const
106 diff --git a/lib/engine/components/echo/echo-simple.h b/lib/engine/components/echo/echo-simple.h
107 index 1c6a307..4c94946 100644
108 --- a/lib/engine/components/echo/echo-simple.h
109 +++ b/lib/engine/components/echo/echo-simple.h
110 @@ -56,11 +56,15 @@ namespace Echo
111 void disconnect (gmref_ptr<Ekiga::ChatObserver> observer);
113 bool send_message (const std::string msg);
115 + void display_message (const std::string msg);
117 Ekiga::PresentityPtr get_presentity () const;
119 bool populate_menu (Ekiga::MenuBuilder &builder);
121 + bool is_real_time_text_enabled () { return false; }
123 private:
125 std::list<gmref_ptr<Ekiga::ChatObserver> > observers;
126 diff --git a/lib/engine/components/opal/opal-call-manager.cpp b/lib/engine/components/opal/opal-call-manager.cpp
127 index 2961d8a..0771175 100644
128 --- a/lib/engine/components/opal/opal-call-manager.cpp
129 +++ b/lib/engine/components/opal/opal-call-manager.cpp
130 @@ -141,6 +141,13 @@ CallManager::CallManager (Ekiga::ServiceCore & _core)
131 queue = g_async_queue_new ();
133 PInterfaceMonitor::GetInstance().SetRefreshInterval (15000);
135 + // IM media format
136 + using_im = false;
137 + using_im_media_format = OpalT140;
138 + im_media_format = OpalMediaFormat();
139 + t140_buffer_time = 300;
140 + t140_cps = 30;
144 @@ -156,7 +163,7 @@ void CallManager::set_display_name (const std::string & name)
146 display_name = name;
148 - SetDefaultDisplayName (display_name);
149 + SetDefaultDisplayName ("");
153 @@ -357,7 +364,8 @@ void CallManager::set_codecs (Ekiga::CodecList & _codecs)
155 codecs = _codecs;
158 + // T140 is the first order and not in the mask, otherwise setup t140 session will fail.
159 + order += OpalT140;
161 // Update OPAL
163 @@ -496,6 +504,28 @@ bool CallManager::dial (const std::string & uri)
164 return false;
167 +bool
168 +CallManager::make_im_connection (const std::string & uri)
170 + std::stringstream ustr;
172 + if (uri.find ("sip:") == 0 || uri.find (":") == string::npos) {
174 + if (uri.find (":") == string::npos)
175 + ustr << "sip:" << uri;
176 + else
177 + ustr << uri;
179 + PSafePtr<OpalCall> call = FindCallWithLock(tokens[uri]);
180 + if (call) {
181 + OpalConnection::StringOptions * options = new OpalConnection::StringOptions();
182 + //options->SetAt(OPAL_OPT_AUTO_START, get_im_media_format().GetMediaType() + ":exclusive");
183 + options->SetAt(OPAL_OPT_AUTO_START, get_im_media_format().GetMediaType());
184 + return MakeConnection(*call, ustr.str(), (void*) ustr.str().c_str(), 0, options);
187 + return false;
190 void CallManager::set_video_options (const CallManager::VideoOptions & options)
192 @@ -616,6 +646,45 @@ void CallManager::get_video_options (CallManager::VideoOptions & options) const
196 +bool CallManager::is_using_im (void)
198 + return using_im;
201 +const OpalMediaFormat &CallManager::get_using_im_media_format (void)
203 + return using_im_media_format;
206 +void CallManager::set_im_media_format (OpalMediaFormat media_format)
208 + im_media_format = media_format;
211 +OpalMediaFormat &CallManager::get_im_media_format (void)
213 + return im_media_format;
216 +void CallManager::set_t140_buffer_time (int buffer_time)
218 + t140_buffer_time = buffer_time;
221 +int CallManager::get_t140_buffer_time () const
223 + return t140_buffer_time;
226 +void CallManager::set_t140_cps (int cps)
228 + t140_cps = cps;
231 +int CallManager::get_t140_cps () const
233 + return t140_cps;
236 OpalCall *CallManager::CreateCall (void *uri)
238 @@ -644,11 +713,16 @@ CallManager::DestroyCall (OpalCall *_call)
239 void
240 CallManager::OnClosedMediaStream (const OpalMediaStream & stream)
242 + if (stream.GetMediaFormat() == OpalT140) {
243 + using_im = false;
246 OpalMediaFormatList list = pcssEP->GetMediaFormats ();
247 OpalManager::OnClosedMediaStream (stream);
249 if (list.FindFormat(stream.GetMediaFormat()) != list.end ())
250 dynamic_cast <Opal::Call &> (stream.GetConnection ().GetCall ()).OnClosedMediaStream ((OpalMediaStream &) stream);
255 @@ -658,14 +732,50 @@ CallManager::OnOpenMediaStream (OpalConnection & connection,
257 OpalMediaFormatList list = pcssEP->GetMediaFormats ();
258 if (!OpalManager::OnOpenMediaStream (connection, stream))
259 - return FALSE;
260 + return false;
262 if (list.FindFormat(stream.GetMediaFormat()) == list.end ())
263 dynamic_cast <Opal::Call &> (connection.GetCall ()).OnOpenMediaStream (stream);
265 - return TRUE;
266 + if (stream.GetMediaFormat() == OpalT140) {
267 + // Do not enable T140
268 + if (im_media_format != OpalT140) {
269 + PTRACE(1, "CallManager\tOnOpenMediaStream disable t140.");
270 + return false;
272 + PTRACE(1, "CallManager\tOnOpenMediaStream enable t140.");
273 + using_im = true;
274 + using_im_media_format = OpalT140;
275 +// stream.GetMediaFormat().PrintOptions(cout);
276 +// cout << endl;
277 +// stream.GetMediaFormat().SetOptionInteger("cps", get_t140_cps());
278 +// stream.GetMediaFormat().PrintOptions(cout);
279 +// cout << endl;
282 + return true;
286 +void CallManager::OnEstablished(OpalConnection &connection)
288 + std::string disp_name = (const char *) connection.GetRemotePartyName ();
289 + std::string uri = (const char *) "sip:" + disp_name;
290 + // For T.140
291 + tokens[uri] = connection.GetCall().GetToken();
293 + OpalManager::OnEstablished(connection);
296 +void CallManager::OnReleased(OpalConnection &connection)
298 + std::string disp_name = (const char *) connection.GetRemotePartyName ();
299 + std::string uri = (const char *) "sip:" + disp_name;
300 + tokens.erase (uri);
302 + using_im = false;
303 + OpalManager::OnReleased(connection);
306 void CallManager::GetAllowedFormats (OpalMediaFormatList & full_list)
308 @@ -755,3 +865,4 @@ CallManager::ReportSTUNError (const std::string error)
309 10);
313 diff --git a/lib/engine/components/opal/opal-call-manager.h b/lib/engine/components/opal/opal-call-manager.h
314 index 421502e..75fa340 100644
315 --- a/lib/engine/components/opal/opal-call-manager.h
316 +++ b/lib/engine/components/opal/opal-call-manager.h
317 @@ -88,6 +88,8 @@ public:
318 /** Call Manager **/
319 bool dial (const std::string & uri);
321 + bool make_im_connection (const std::string & uri);
323 void set_display_name (const std::string & name);
324 const std::string & get_display_name () const;
326 @@ -151,6 +153,21 @@ public:
327 void set_video_options (const VideoOptions & options);
328 void get_video_options (VideoOptions & options) const;
330 + /* T140 */
331 + bool is_using_im (void);
332 + const OpalMediaFormat &get_using_im_media_format (void);
334 + void set_im_media_format (OpalMediaFormat im_media_format);
335 + OpalMediaFormat &get_im_media_format (void);
337 + void set_t140_buffer_time (int buffer_time);
338 + int get_t140_buffer_time () const;
340 + void set_t140_cps (int cps);
341 + int get_t140_cps () const;
343 + PString &find_token_with_uri (const PString &uri) { return tokens[uri]; }
345 private:
346 OpalCall *CreateCall (void *uri);
347 void DestroyCall (OpalCall *);
348 @@ -160,6 +177,10 @@ private:
350 void OnClosedMediaStream (const OpalMediaStream &);
352 + void OnEstablished (OpalConnection &connection);
354 + void OnReleased (OpalConnection &connection);
356 void GetAllowedFormats (OpalMediaFormatList & full_list);
358 void HandleSTUNResult ();
359 @@ -187,6 +208,15 @@ private:
360 bool unconditional_forward;
361 bool forward_on_no_answer;
362 bool stun_enabled;
364 + std::map<std::string, PString> tokens; // <uri, token>
366 + /* which im format to use */
367 + bool using_im;
368 + OpalMediaFormat using_im_media_format;
369 + OpalMediaFormat im_media_format;
370 + int t140_buffer_time;
371 + int t140_cps;
374 #endif
375 diff --git a/lib/engine/components/opal/opal-gmconf-bridge.cpp b/lib/engine/components/opal/opal-gmconf-bridge.cpp
376 index baf5d8b..aef24a7 100644
377 --- a/lib/engine/components/opal/opal-gmconf-bridge.cpp
378 +++ b/lib/engine/components/opal/opal-gmconf-bridge.cpp
379 @@ -60,6 +60,7 @@
380 #define SIP_KEY "/apps/" PACKAGE_NAME "/protocols/sip/"
381 #define PORTS_KEY "/apps/" PACKAGE_NAME "/protocols/ports/"
382 #define CALL_FORWARDING_KEY "/apps/" PACKAGE_NAME "/protocols/call_forwarding/"
383 +#define TEXT_KEY "/apps/" PACKAGE_NAME "/protocols/t140/"
384 #define AUDIO_CODECS_KEY "/apps/" PACKAGE_NAME "/codecs/audio/"
385 #define VIDEO_CODECS_KEY "/apps/" PACKAGE_NAME "/codecs/video/"
387 @@ -78,6 +79,10 @@ ConfBridge::ConfBridge (Ekiga::Service & _service)
388 keys.push_back (AUDIO_CODECS_KEY "enable_silence_detection");
389 keys.push_back (AUDIO_CODECS_KEY "enable_echo_cancelation");
391 + keys.push_back (TEXT_KEY "enable_realtime");
392 + keys.push_back (TEXT_KEY "buffer_time");
393 + keys.push_back (TEXT_KEY "character_per_second");
395 keys.push_back (AUDIO_CODECS_KEY "media_list");
396 keys.push_back (VIDEO_CODECS_KEY "media_list");
398 @@ -289,6 +294,31 @@ void ConfBridge::on_property_changed (std::string key, GmConfEntry *entry)
402 + // TEXT related keys
403 + //
404 + else if (key.find (TEXT_KEY) != string::npos) {
406 + if (key == TEXT_KEY "buffer_time") {
408 + manager.set_t140_buffer_time (gm_conf_entry_get_int (entry));
410 + else if (key == TEXT_KEY "character_per_second") {
412 + manager.set_t140_cps (gm_conf_entry_get_int (entry));
414 + else if (key == TEXT_KEY "enable_realtime") {
415 + if (gm_conf_entry_get_bool (entry)) {
417 + PTRACE(1, "opal-gmconf-bridge\tEnable t140.");
418 + manager.set_im_media_format(OpalT140);
419 + } else {
420 + PTRACE(1, "opal-gmconf-bridge\tDisable t140.");
421 + manager.set_im_media_format(OpalMediaFormat ());
426 + //
427 // H.323 keys
429 #ifdef HAVE_H323
430 diff --git a/lib/engine/components/opal/pcss-endpoint.cpp b/lib/engine/components/opal/pcss-endpoint.cpp
431 index 8727fb1..68099b2 100644
432 --- a/lib/engine/components/opal/pcss-endpoint.cpp
433 +++ b/lib/engine/components/opal/pcss-endpoint.cpp
434 @@ -40,10 +40,10 @@
436 #include "pcss-endpoint.h"
437 #include "opal-call-manager.h"
438 +#include "sip-endpoint.h"
440 #include "call.h"
443 GMPCSSEndpoint::GMPCSSEndpoint (Opal::CallManager & ep,
444 Ekiga::ServiceCore & _core)
445 : OpalPCSSEndPoint (ep),
446 @@ -54,16 +54,32 @@ GMPCSSEndpoint::GMPCSSEndpoint (Opal::CallManager & ep,
447 #else
448 SetSoundChannelBufferDepth (5);
449 #endif
454 -bool GMPCSSEndpoint::OnShowIncoming (const OpalPCSSConnection & /*connection*/)
455 +bool GMPCSSEndpoint::OnShowIncoming (const OpalPCSSConnection & connection)
457 + ((OpalConnection &)connection).AddIMListener(PCREATE_NOTIFIER(OnReceiveIM));
458 return true;
462 -bool GMPCSSEndpoint::OnShowOutgoing (const OpalPCSSConnection & /*connection*/)
463 +bool GMPCSSEndpoint::OnShowOutgoing (const OpalPCSSConnection & connection)
465 + ((OpalConnection &)connection).AddIMListener(PCREATE_NOTIFIER(OnReceiveIM));
466 return true;
469 +void GMPCSSEndpoint::OnReceiveIM(OpalConnection::IMInfo & im, INT conn)
471 + OpalConnection *connection = (OpalConnection *) conn;
473 + std::string display_name = (const char *) connection->GetRemotePartyName ();
474 + std::string message_uri = (const char *) "sip:" + display_name;
475 + std::string message = (const char *)im.body.GetPointer();
477 + OpalEndPoint *sip = GetManager().FindEndPoint ("sip");
478 + dynamic_cast<Opal::Sip::EndPoint*>(sip)->OnReceivedIM(message_uri, display_name, message, (void *)conn);
481 diff --git a/lib/engine/components/opal/pcss-endpoint.h b/lib/engine/components/opal/pcss-endpoint.h
482 index 4ee2ea3..300c381 100644
483 --- a/lib/engine/components/opal/pcss-endpoint.h
484 +++ b/lib/engine/components/opal/pcss-endpoint.h
485 @@ -45,6 +45,8 @@
486 #include <opal/opal.h>
487 #include <opal/pcss.h>
489 +#include "chat-core.h"
491 namespace Opal {
492 class CallManager;
494 @@ -60,7 +62,10 @@ public:
496 bool OnShowOutgoing (const OpalPCSSConnection &connection);
498 + PDECLARE_NOTIFIER(OpalConnection::IMInfo, GMPCSSEndpoint, OnReceiveIM);
500 private:
502 Ekiga::ServiceCore & core;
505 diff --git a/lib/engine/components/opal/sip-chat-simple.cpp b/lib/engine/components/opal/sip-chat-simple.cpp
506 index aa23eff..d99a6aa 100644
507 --- a/lib/engine/components/opal/sip-chat-simple.cpp
508 +++ b/lib/engine/components/opal/sip-chat-simple.cpp
509 @@ -47,6 +47,7 @@ SIP::SimpleChat::SimpleChat (Ekiga::ServiceCore& core_,
511 presentity = gmref_ptr<Ekiga::URIPresentity> (new Ekiga::URIPresentity (core, name, uri,
512 std::set<std::string>()));
513 + call_manager = core.get ("opal-component");
516 SIP::SimpleChat::~SimpleChat ()
517 @@ -85,13 +86,20 @@ bool
518 SIP::SimpleChat::send_message (const std::string msg)
520 bool result;
521 - gmref_ptr<Ekiga::PersonalDetails> personal = core.get ("personal-details");
522 + //gmref_ptr<Ekiga::PersonalDetails> personal = core.get ("personal-details");
523 result = sender (msg);
525 + return result;
528 +void
529 +SIP::SimpleChat::display_message (const std::string msg)
531 + gmref_ptr<Ekiga::PersonalDetails> personal = core.get ("personal-details");
532 for (std::list<gmref_ptr<Ekiga::ChatObserver> >::iterator iter = observers.begin ();
533 iter != observers.end ();
534 ++iter)
535 - (*iter)->message (personal->get_display_name (), msg);
536 - return result;
537 + (*iter)->message (personal->get_display_name (), msg, false);
540 void
541 @@ -100,7 +108,7 @@ SIP::SimpleChat::receive_message (const std::string msg)
542 for (std::list<gmref_ptr<Ekiga::ChatObserver> >::iterator iter = observers.begin ();
543 iter != observers.end ();
544 ++iter)
545 - (*iter)->message (presentity->get_name (), msg);
546 + (*iter)->message (presentity->get_name (), msg, true);
549 void
550 @@ -123,3 +131,15 @@ SIP::SimpleChat::populate_menu (Ekiga::MenuBuilder& /*builder*/)
552 return false;
555 +bool
556 +SIP::SimpleChat::is_real_time_text_enabled ()
558 + return call_manager->is_using_im();
561 +int
562 +SIP::SimpleChat::real_time_buffering_time ()
564 + return call_manager->get_t140_buffer_time();
566 diff --git a/lib/engine/components/opal/sip-chat-simple.h b/lib/engine/components/opal/sip-chat-simple.h
567 index 7a3de61..5e15814 100644
568 --- a/lib/engine/components/opal/sip-chat-simple.h
569 +++ b/lib/engine/components/opal/sip-chat-simple.h
570 @@ -40,6 +40,7 @@
572 #include "chat-simple.h"
573 #include "services.h"
574 +#include "opal-call-manager.h"
576 namespace SIP
578 @@ -63,6 +64,8 @@ namespace SIP
580 bool send_message (const std::string msg);
582 + void display_message (const std::string msg);
584 void receive_message (const std::string msg);
586 void receive_notice (const std::string msg);
587 @@ -71,6 +74,10 @@ namespace SIP
589 bool populate_menu (Ekiga::MenuBuilder& builder);
591 + bool is_real_time_text_enabled ();
593 + int real_time_buffering_time ();
595 private:
597 Ekiga::ServiceCore& core;
598 @@ -78,6 +85,7 @@ namespace SIP
599 std::list<gmref_ptr<Ekiga::ChatObserver> > observers;
600 Ekiga::PresentityPtr presentity;
601 std::string uri;
602 + gmref_ptr<Opal::CallManager> call_manager;
605 typedef gmref_ptr<SimpleChat> SimpleChatPtr;
606 diff --git a/lib/engine/components/opal/sip-endpoint.cpp b/lib/engine/components/opal/sip-endpoint.cpp
607 index ece5f98..85d1171 100644
608 --- a/lib/engine/components/opal/sip-endpoint.cpp
609 +++ b/lib/engine/components/opal/sip-endpoint.cpp
610 @@ -352,15 +352,24 @@ Opal::Sip::EndPoint::send_message (const std::string & _uri,
612 if (!_uri.empty () && (_uri.find ("sip:") == 0 || _uri.find (':') == string::npos) && !_message.empty ()) {
614 - SIPEndPoint::Message (_uri, _message);
616 + if (manager.is_using_im()) {
617 + PSafePtr<OpalCall> call = manager.FindCallWithLock(manager.find_token_with_uri(_uri));
619 + if (call != NULL) {
620 + PSafePtr<OpalPCSSConnection> conn = call->GetConnectionAs<OpalPCSSConnection>();
621 + if (conn != NULL) {
622 + conn->SendIM(manager.get_using_im_media_format(), T140String(_message));
625 + } else {
626 + SIPEndPoint::Message (_uri, _message);
628 return true;
631 return false;
635 bool
636 Opal::Sip::EndPoint::dial (const std::string & uri)
638 @@ -373,8 +382,14 @@ Opal::Sip::EndPoint::dial (const std::string & uri)
639 else
640 ustr << uri;
642 - PString token;
643 - manager.SetUpCall("pc:*", ustr.str(), token, (void*) ustr.str().c_str());
644 + OpalConnection::StringOptions *options = NULL;
646 + if (manager.get_im_media_format() == OpalT140) {
647 + options = new OpalConnection::StringOptions();
648 + options->SetAt(OPAL_OPT_AUTO_START, manager.get_im_media_format().GetMediaType());
651 + manager.SetUpCall("pc:*", ustr.str(), manager.find_token_with_uri(uri), (void*) ustr.str().c_str(), 0, options);
653 return true;
655 @@ -382,7 +397,6 @@ Opal::Sip::EndPoint::dial (const std::string & uri)
656 return false;
660 const std::string&
661 Opal::Sip::EndPoint::get_protocol_name () const
663 @@ -890,6 +904,7 @@ Opal::Sip::EndPoint::OnIncomingConnection (OpalConnection &connection,
664 else {
666 Opal::Call *call = dynamic_cast<Opal::Call *> (&connection.GetCall ());
668 if (call) {
670 if (!forward_uri.empty () && manager.get_forward_on_no_answer ())
671 @@ -911,7 +926,6 @@ Opal::Sip::EndPoint::OnReceivedMESSAGE (OpalTransport & transport,
673 PString *last = NULL;
674 PString *val = NULL;
676 PString from = pdu.GetMIME().GetFrom();
677 PINDEX j = from.Find (';');
678 if (j != P_MAX_INDEX)
679 @@ -939,6 +953,14 @@ Opal::Sip::EndPoint::OnReceivedMESSAGE (OpalTransport & transport,
680 return SIPEndPoint::OnReceivedMESSAGE (transport, pdu);
683 +void
684 +Opal::Sip::EndPoint::OnReceivedIM (std::string &uri,
685 + std::string &display_name,
686 + std::string &message,
687 + void *conn)
689 + Ekiga::Runtime::run_in_main (sigc::bind (sigc::mem_fun (this, &Opal::Sip::EndPoint::push_message_in_main), uri, display_name, message));
692 void
693 Opal::Sip::EndPoint::OnMessageFailed (const SIPURL & messageUrl,
694 @@ -954,7 +976,6 @@ Opal::Sip::EndPoint::OnMessageFailed (const SIPURL & messageUrl,
695 _("Could not send message")));
699 SIPURL
700 Opal::Sip::EndPoint::GetRegisteredPartyName (const SIPURL & aor,
701 const OpalTransport & transport)
702 diff --git a/lib/engine/components/opal/sip-endpoint.h b/lib/engine/components/opal/sip-endpoint.h
703 index 7fbd6b2..5c6598c 100644
704 --- a/lib/engine/components/opal/sip-endpoint.h
705 +++ b/lib/engine/components/opal/sip-endpoint.h
706 @@ -114,7 +114,6 @@ namespace Opal {
707 bool send_message (const std::string & uri,
708 const std::string & message);
711 /* CallProtocolManager */
712 bool dial (const std::string & uri);
714 @@ -180,13 +179,17 @@ namespace Opal {
715 bool OnReceivedMESSAGE (OpalTransport & transport,
716 SIP_PDU & pdu);
718 + void OnReceivedIM (std::string &uri,
719 + std::string &display_name,
720 + std::string &message,
721 + void *conn);
723 void OnMessageFailed (const SIPURL & messageUrl,
724 SIP_PDU::StatusCodes reason);
726 SIPURL GetRegisteredPartyName (const SIPURL & host,
727 const OpalTransport & transport);
730 /* Callbacks */
731 private:
732 void on_dial (std::string uri);
733 diff --git a/lib/engine/gui/gtk-frontend/chat-area.cpp b/lib/engine/gui/gtk-frontend/chat-area.cpp
734 index 663ee68..14ea57a 100644
735 --- a/lib/engine/gui/gtk-frontend/chat-area.cpp
736 +++ b/lib/engine/gui/gtk-frontend/chat-area.cpp
737 @@ -55,6 +55,12 @@
739 class ChatAreaHelper;
741 +struct _HistoryMessage
743 + gint number;
744 + GSList* next;
747 struct _ChatAreaPrivate
749 Ekiga::Chat* chat;
750 @@ -67,6 +73,15 @@ struct _ChatAreaPrivate
751 GtkWidget* scrolled_text_window;
752 GtkWidget* text_view;
753 GtkWidget* message;
754 + GTimeVal buffering_timer_stop_time;
755 + guint buffering_timer_id;
756 + gint buffering_time;
757 + gint bp;
758 + gint cp_min;
759 + gint line_number;
760 + GHashTable* hash;
761 + GSList* list;
762 + gchar* local_name;
765 enum {
766 @@ -84,13 +99,23 @@ static GObjectClass* parent_class = NULL;
768 /* declaration of internal api */
770 +static gboolean message_send_after_buffering (gpointer data);
772 +static void start_buffering_timer (ChatArea* self);
774 +static gboolean buffering_timer_is_started (ChatArea* self);
776 static void chat_area_add_notice (ChatArea* self,
777 const gchar* txt);
779 -static void chat_area_add_message (ChatArea* self,
780 +static void chat_area_add_local_message (ChatArea* self,
781 const gchar* from,
782 const gchar* txt);
784 +static void chat_area_add_remote_message (ChatArea* self,
785 + const gchar* from,
786 + const gchar* txt);
788 /* declaration of the helping observer */
789 class ChatAreaHelper: public Ekiga::ChatObserver
791 @@ -102,8 +127,15 @@ public:
794 void message (const std::string from,
795 - const std::string msg)
796 - { chat_area_add_message (area, from.c_str (), msg.c_str ()); }
797 + const std::string msg,
798 + bool flag)
800 + if (flag) {
801 + chat_area_add_remote_message (area, from.c_str (), msg.c_str ());
802 + } else {
803 + chat_area_add_local_message (area, from.c_str (), msg.c_str ());
807 void notice (const std::string msg)
808 { chat_area_add_notice (area, msg.c_str ()); }
809 @@ -154,6 +186,12 @@ static gboolean message_activated_cb (GtkWidget *w,
810 GdkEventKey *key,
811 gpointer data);
813 +static void message_changed_cb (GtkTextBuffer *textbuffer,
814 + gpointer user_data);
816 +static void backspace_activated_cb (GtkTextView *textview,
817 + gpointer user_data);
819 static void on_chat_removed (ChatArea* self);
821 static void on_chat_area_grab_focus (GtkWidget*,
822 @@ -210,6 +248,90 @@ gm_chat_area_define_simple_text_tag (GtkTextBuffer* buffer,
823 * owned by the buffer's tag table */
826 +static gboolean
827 +message_send_after_buffering (gpointer data)
829 + ChatArea *self = CHAT_AREA (data);
830 + GtkTextIter cp_min_iter, end_iter;
831 + GtkTextBuffer *buffer = NULL;
832 + gchar* body = NULL;
833 + gint cp = 0; // cursor point
835 + g_return_val_if_fail (data != NULL, FALSE);
837 + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->message));
838 + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
839 + cp = gtk_text_iter_get_offset(&end_iter);
841 + if (self->priv->cp_min != self->priv->bp || self->priv->bp != cp) {
843 + if (self->priv->buffering_timer_id > 0) {
844 + send_immediately:
845 + gchar *backspace_str = NULL;
846 + gchar *message = NULL;
848 + gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &cp_min_iter, self->priv->cp_min);
850 + body = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &cp_min_iter, &end_iter, TRUE);
852 + if (self->priv->cp_min < self->priv->bp) {
853 + backspace_str = g_strnfill(self->priv->bp - self->priv->cp_min, '\b');
854 + message = g_strconcat (backspace_str, body, NULL);
855 + g_free(body);
856 + g_free(backspace_str);
857 + } else {
858 + message = body;
861 + if (self->priv->chat->send_message (message)) {
862 + self->priv->bp = cp;
863 + self->priv->cp_min = cp;
866 + g_free(message);
868 + } else {
869 + GTimeVal now;
870 + GTimeVal last = self->priv->buffering_timer_stop_time;
871 + /* Detect if it is after an idle period time (a buffering time) */
872 + g_get_current_time(&now);
873 + g_time_val_add(&last, self->priv->buffering_time);
874 + // Start buffer timer anyway
875 + start_buffering_timer(self);
876 + if (now.tv_sec > last.tv_sec
877 + || (now.tv_sec == last.tv_sec && now.tv_usec == last.tv_usec)) {
878 + // Send at once
879 + goto send_immediately;
880 + // } else {
881 + // postpone to the next buffering time
884 + } else {
885 + // No changes
886 + /* Update timer stop time */
887 + g_get_current_time(&self->priv->buffering_timer_stop_time);
888 + self->priv->buffering_timer_id = 0;
889 + return FALSE;
892 + return TRUE;
895 +static void
896 +start_buffering_timer (ChatArea* self)
898 + if (self->priv->buffering_timer_id == 0) {
899 + self->priv->buffering_timer_id = g_timeout_add (self->priv->buffering_time,
900 + (GSourceFunc)message_send_after_buffering,
901 + self);
905 +static gboolean
906 +buffering_timer_is_started (ChatArea* self)
908 + return self->priv->buffering_timer_id != 0;
911 static void
912 chat_area_add_notice (ChatArea* self,
913 @@ -235,25 +357,188 @@ chat_area_add_notice (ChatArea* self,
916 static void
917 -chat_area_add_message (ChatArea* self,
918 - const gchar* from,
919 - const gchar* txt)
920 +chat_area_add_local_message (ChatArea* self,
921 + const gchar* from,
922 + const gchar* txt)
924 gchar* str = NULL;
925 GtkTextMark *mark = NULL;
926 GtkTextBuffer* buffer = NULL;
927 GtkTextIter iter;
929 - str = g_strdup_printf ("<b><i>%s %s</i></b>\n%s\n", from, _("says:"), txt);
930 + str = g_strdup_printf ("<b><i>%s %s</i></b>\n%s", from, _("says:"), txt);
931 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->text_view));
932 gtk_text_buffer_get_end_iter (buffer, &iter);
933 - gm_text_buffer_enhancer_insert_text (self->priv->enhancer, &iter,
934 - str, -1);
936 + if (self->priv->chat->is_real_time_text_enabled()) {
937 + gtk_text_iter_set_line (&iter, self->priv->line_number);
938 + gm_text_buffer_enhancer_insert_text (self->priv->enhancer, &iter,
939 + str, -1);
941 + self->priv->line_number = gtk_text_iter_get_line (&iter);
942 + g_free (self->priv->local_name);
943 + self->priv->local_name = g_strdup (from);
945 + _HistoryMessage* history_message = g_new (_HistoryMessage, 1);
946 + history_message->number = self->priv->line_number;
947 + history_message->next = (GSList*)g_hash_table_lookup (self->priv->hash, from);
949 + self->priv->list = g_slist_prepend (self->priv->list, history_message);
951 + g_hash_table_insert (self->priv->hash, (gpointer)g_strdup(from), (gpointer)(self->priv->list));
953 + } else {
954 + gm_text_buffer_enhancer_insert_text (self->priv->enhancer, &iter,
955 + str, -1);
959 g_free (str);
961 mark = gtk_text_buffer_get_mark (buffer, "current-position");
962 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (self->priv->text_view), mark,
963 - 0.0, FALSE, 0,0);
964 + 0.0, FALSE, 0,0);
966 + g_signal_emit (self, signals[MESSAGE_NOTICE_EVENT], 0);
970 +static void
971 +chat_area_add_remote_message (ChatArea* self,
972 + const gchar* from,
973 + const gchar* txt)
975 +#define ZERO_WIDTH_NO_BREAK 0xfeff
976 + GtkTextMark *mark = NULL;
977 + GtkTextBuffer* buffer = NULL;
978 + GtkTextIter start_iter, end_iter;
979 + gchar* str = NULL;
980 + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->text_view));
981 + gtk_text_buffer_get_end_iter (buffer, &end_iter);
983 + if (self->priv->chat->is_real_time_text_enabled()) {
985 + g_return_if_fail(g_utf8_validate(txt, -1, NULL));
986 + gchar *iter = (gchar *)txt;
987 + glong len = g_utf8_strlen(txt, -1);
988 + glong i = 0;
989 + gunichar uc;
991 + while(i < len) {
992 + uc = g_utf8_get_char(iter);
993 + g_message("Get unichar 0x%x", uc);
995 + if (uc == '\n') {
996 + gboolean flag;
997 + gchar *body = NULL;
999 + gtk_text_buffer_get_end_iter (buffer, &start_iter);
1000 + gtk_text_iter_set_line (&start_iter, -1);
1002 + body = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter, TRUE);
1003 + flag = gtk_text_iter_backward_line(&start_iter);
1005 + gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter);
1006 + str = g_strdup_printf ("<b><i>%s %s</i></b>\n%s\n", from, _("says:"), body);
1007 + gm_text_buffer_enhancer_insert_text (self->priv->enhancer, &end_iter,
1008 + str, -1);
1010 + gtk_text_buffer_get_end_iter (buffer, &end_iter);
1011 + self->priv->line_number = gtk_text_iter_get_line (&end_iter);
1013 + _HistoryMessage* history_message = g_new (_HistoryMessage, 1);
1014 + history_message->number = self->priv->line_number;
1015 + history_message->next = (GSList*)g_hash_table_lookup (self->priv->hash, from);
1017 + self->priv->list = g_slist_prepend (self->priv->list, history_message);
1019 + g_hash_table_insert(self->priv->hash, (gpointer)g_strdup(from), (gpointer)(self->priv->list));
1021 + g_free (body);
1023 + } else if(uc == '\b') {
1025 + GSList* lookup_ptr = (GSList*)g_hash_table_lookup (self->priv->hash, from);
1027 + if (0 == gtk_text_iter_get_line_offset (&end_iter) && (lookup_ptr != NULL)) {
1029 + _HistoryMessage* _historymessage = (_HistoryMessage*)(lookup_ptr->data);
1030 + gint from_number = (_historymessage)->number;
1031 + gboolean flag;
1032 + gchar* body = NULL;
1033 + GSList* ptr = NULL;
1035 + gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start_iter);
1036 + gtk_text_iter_set_line (&start_iter, from_number-1);
1038 + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
1039 + gtk_text_iter_set_line (&end_iter, from_number-1);
1040 + gtk_text_iter_forward_to_line_end (&end_iter);
1042 + body = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter, TRUE);
1043 + flag = gtk_text_iter_backward_line (&start_iter);
1044 + flag = gtk_text_iter_forward_char (&end_iter);
1045 + gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter);
1047 + for (ptr = self->priv->list;
1048 + ptr!= lookup_ptr;
1049 + ptr = g_slist_next (ptr)) {
1050 + ((_HistoryMessage*)(ptr->data))->number -= 2;
1051 + }
1053 + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
1054 + str = g_strdup_printf ("<b>%s %s</b>\n%s", from, _("is typing:"), body);
1055 + gm_text_buffer_enhancer_insert_text (self->priv->enhancer, &end_iter,
1056 + str, -1);
1057 + g_free (body);
1059 + self->priv->line_number -= 2;
1061 + g_hash_table_insert (self->priv->hash, (gpointer)g_strdup (from), (gpointer)(_historymessage->next));
1062 + g_free (_historymessage);
1063 + self->priv->list = g_slist_delete_link (self->priv->list, lookup_ptr);
1065 + } else {
1066 + gtk_text_buffer_get_end_iter (buffer, &start_iter);
1067 + gtk_text_iter_backward_char (&start_iter);
1068 + gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter);
1070 + if (0 == gtk_text_iter_get_line_offset (&end_iter)){
1071 + gtk_text_iter_backward_line (&start_iter);
1072 + gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter);
1074 + }
1075 + } else if (uc == ZERO_WIDTH_NO_BREAK) {
1076 + ; // Ignore
1077 + } else {
1078 + gchar out[7];
1080 + out[g_unichar_to_utf8(uc, out)] = '\0';
1081 + gtk_text_buffer_get_start_iter (buffer, &start_iter);
1083 + if (self->priv->line_number == gtk_text_iter_get_line (&end_iter)) {
1084 + str = g_strdup_printf ("<b>%s %s</b>\n%s", from, _("is typing:"), out);
1085 + } else {
1086 + str = g_strdup(out);
1089 + gm_text_buffer_enhancer_insert_text (self->priv->enhancer, &end_iter,
1090 + str, -1);
1093 + iter = g_utf8_next_char(iter);
1094 + i++;
1096 + } else {
1097 + str = g_strdup_printf ("<b><i>%s %s</i></b>\n%s", from, _("says:"), txt);
1098 + gm_text_buffer_enhancer_insert_text (self->priv->enhancer, &end_iter,
1099 + str, -1);
1101 + g_free (str);
1103 + mark = gtk_text_buffer_get_mark (buffer, "current-position");
1104 + gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (self->priv->text_view), mark,
1105 + 0.0, FALSE, 0,0);
1107 g_signal_emit (self, signals[MESSAGE_NOTICE_EVENT], 0);
1109 @@ -547,32 +832,150 @@ message_activated_cb (G_GNUC_UNUSED GtkWidget *w,
1110 gpointer data)
1112 ChatArea *self = CHAT_AREA (data);
1113 - GtkTextIter start_iter, end_iter;
1114 + GtkTextIter end_iter;
1115 GtkTextBuffer *buffer = NULL;
1116 - gchar *body = NULL;
1117 - std::string message;
1119 g_return_val_if_fail (data != NULL, false);
1121 - if (key->keyval == GDK_Return) {
1123 + if (self->priv->chat->is_real_time_text_enabled()) {
1124 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->message));
1125 - gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start_iter);
1126 gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
1127 + gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (buffer), &end_iter);
1130 + return false;
1133 +static void
1134 +message_changed_cb (GtkTextBuffer *buffer, gpointer data)
1136 + ChatArea *self = CHAT_AREA (data);
1137 + GtkTextIter start_iter, end_iter, last_iter;
1138 + gchar* body = NULL;
1139 + gunichar keyval;
1140 + gboolean realtime_im = self->priv->chat->is_real_time_text_enabled();
1142 + g_return_if_fail (data != NULL);
1144 + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->message));
1145 + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
1146 + last_iter = end_iter;
1147 + gint offset = gtk_text_iter_get_offset(&end_iter);
1149 + if (gtk_text_iter_backward_char(&last_iter)) {
1150 + keyval = gtk_text_iter_get_char (&last_iter);
1152 + if (keyval == '\n') {
1154 + gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start_iter);
1156 + if (offset == 1) {
1157 + // Only a Return
1158 + gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter);
1159 + return;
1162 - /* if nothing to send - send nothing ;-) */
1163 - if (gtk_text_iter_get_offset (&end_iter) == 0)
1164 - return TRUE;
1165 + body = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter, TRUE);
1167 + self->priv->chat->display_message (body);
1169 - body = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter, TRUE);
1170 + if (!realtime_im) {
1171 + self->priv->chat->send_message (body);
1172 + } else {
1173 + // Start buffer timer anyway, so we can make sure message must
1174 + // be sent.
1175 + start_buffering_timer(self);
1176 + message_send_after_buffering(data);
1178 + // Reset pointer since we are clean the input buffer.
1179 + self->priv->bp = 0;
1180 + self->priv->cp_min = 0;
1183 - if (self->priv->chat->send_message (body))
1184 gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter);
1186 - return true;
1187 + g_free (body);
1189 + return;
1193 - return false;
1194 + if (realtime_im) {
1195 + if (self->priv->cp_min > offset) {
1196 + self->priv->cp_min = offset;
1199 + gtk_text_buffer_place_cursor(buffer, &end_iter);
1201 + if (!buffering_timer_is_started(self)) {
1202 + message_send_after_buffering(data);
1207 +static void
1208 +backspace_activated_cb (GtkTextView *textview, gpointer data)
1210 + ChatArea *self = CHAT_AREA (data);
1211 + GtkTextIter start_iter, end_iter, last_iter;
1212 + gchar* body = NULL;
1213 + g_return_if_fail (data != NULL);
1215 + GtkTextBuffer* buffer = gtk_text_view_get_buffer (textview);
1216 + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
1217 + last_iter = end_iter;
1218 + gint offset = gtk_text_iter_get_offset (&end_iter);
1220 + if (self->priv->chat->is_real_time_text_enabled()) {
1221 + GSList* lookup_ptr = (GSList*)g_hash_table_lookup (self->priv->hash, self->priv->local_name);
1223 + if ((offset == 0) && (lookup_ptr != NULL)) {
1225 + _HistoryMessage* _historymessage = (_HistoryMessage*)(lookup_ptr->data);
1226 + gint from_number = _historymessage->number;
1227 + gboolean flag;
1228 + GSList* ptr = NULL;
1229 + glong len = 0;
1231 + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->text_view));
1232 + gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start_iter);
1233 + gtk_text_iter_set_line (&start_iter, from_number-1);
1235 + gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (buffer), &end_iter);
1236 + gtk_text_iter_set_line (&end_iter, from_number-1);
1237 + gtk_text_iter_forward_to_line_end (&end_iter);
1239 + body = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter, TRUE);
1240 + // len does not contain "\n"
1241 + len = g_utf8_strlen (body, -1);
1243 + flag = gtk_text_iter_forward_char (&end_iter);
1244 + flag = gtk_text_iter_backward_line (&start_iter);
1245 + gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start_iter, &end_iter);
1247 + for(ptr = self->priv->list;
1248 + ptr!= lookup_ptr;
1249 + ptr = g_slist_next (ptr)) {
1250 + ((_HistoryMessage*)(ptr->data))->number -= 2;
1251 + }
1253 + self->priv->line_number -= 2;
1255 + g_hash_table_insert(self->priv->hash, (gpointer)g_strdup (self->priv->local_name), (gpointer)(_historymessage->next));
1257 + g_free (_historymessage);
1258 + self->priv->list = g_slist_delete_link (self->priv->list, lookup_ptr);
1260 + self->priv->cp_min = len;
1261 + self->priv->bp += len + 1;
1263 + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->message));
1264 + gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (buffer), &start_iter);
1265 + gtk_text_buffer_insert (buffer, &start_iter, body, -1);
1267 + g_free (body);
1272 static void
1273 @@ -637,6 +1040,10 @@ chat_area_finalize (GObject* obj)
1275 self = (ChatArea*)obj;
1277 + if (self->priv->buffering_timer_id > 0) {
1278 + g_source_remove (self->priv->buffering_timer_id);
1281 if (self->priv->chat) {
1283 self->priv->connection.disconnect ();
1284 @@ -647,6 +1054,11 @@ chat_area_finalize (GObject* obj)
1285 self->priv->chat = NULL;
1288 + g_free (self->priv->local_name);
1289 + g_slist_foreach (self->priv->list, (GFunc) g_free, NULL);
1290 + g_slist_free (self->priv->list);
1291 + g_hash_table_destroy(self->priv->hash);
1293 parent_class->finalize (obj);
1296 @@ -691,6 +1103,7 @@ chat_area_set_property (GObject* obj,
1297 self->priv->connection = self->priv->chat->removed.connect (sigc::bind (sigc::ptr_fun (on_chat_removed), self));
1298 self->priv->helper = gmref_ptr<ChatAreaHelper>(new ChatAreaHelper (self));
1299 self->priv->chat->connect (self->priv->helper);
1300 + self->priv->buffering_time = self->priv->chat->real_time_buffering_time();
1301 break;
1303 default:
1304 @@ -757,6 +1170,15 @@ chat_area_init (GTypeInstance* instance,
1305 TYPE_CHAT_AREA,
1306 ChatAreaPrivate);
1307 self->priv->chat = NULL;
1308 + self->priv->buffering_timer_id = 0;
1309 + self->priv->buffering_time = 300;
1310 + self->priv->local_name = g_strdup ("");
1311 + self->priv->bp = 0;
1312 + self->priv->cp_min = 0;
1313 + self->priv->line_number = 0;
1314 + self->priv->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1315 + self->priv->list = NULL;
1318 /* first the area has a text view to display
1319 the GtkScrolledWindow is there to make
1320 @@ -778,7 +1200,7 @@ chat_area_init (GTypeInstance* instance,
1321 gtk_text_view_set_justification (GTK_TEXT_VIEW (self->priv->text_view),
1322 GTK_JUSTIFY_LEFT);
1323 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (self->priv->text_view),
1324 - GTK_WRAP_WORD);
1325 + GTK_WRAP_WORD_CHAR);
1326 gtk_text_view_set_left_margin (GTK_TEXT_VIEW (self->priv->text_view),
1328 gtk_text_view_set_right_margin (GTK_TEXT_VIEW (self->priv->text_view),
1329 @@ -959,11 +1381,22 @@ chat_area_init (GTypeInstance* instance,
1330 gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0);
1332 self->priv->message = gtk_text_view_new ();
1334 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (self->priv->message),
1335 GTK_WRAP_WORD_CHAR);
1336 - gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (self->priv->message), true);
1337 + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (self->priv->message), TRUE);
1339 g_signal_connect (GTK_OBJECT (self->priv->message), "key-press-event",
1340 G_CALLBACK (message_activated_cb), self);
1342 + g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->priv->message)),
1343 + "changed",
1344 + G_CALLBACK (message_changed_cb), self);
1346 + g_signal_connect (GTK_TEXT_VIEW (self->priv->message),
1347 + "backspace",
1348 + G_CALLBACK (backspace_activated_cb), self);
1350 gtk_box_pack_start (GTK_BOX (vbox), self->priv->message,
1351 TRUE, TRUE, 2);
1353 diff --git a/src/common.h b/src/common.h
1354 index 5c3183a..b9407a8 100644
1355 --- a/src/common.h
1356 +++ b/src/common.h
1357 @@ -69,6 +69,7 @@
1358 #define PORTS_KEY "/apps/" PACKAGE_NAME "/protocols/ports/"
1359 #define CALL_FORWARDING_KEY "/apps/" PACKAGE_NAME "/protocols/call_forwarding/"
1360 #define LDAP_KEY "/apps/" PACKAGE_NAME "/protocols/ldap/"
1361 +#define TEXT_KEY "/apps/" PACKAGE_NAME "/protocols/t140/"
1362 #define CODECS_KEY "/apps/" PACKAGE_NAME "/codecs/"
1363 #define AUDIO_CODECS_KEY "/apps/" PACKAGE_NAME "/codecs/audio/"
1364 #define VIDEO_CODECS_KEY "/apps/" PACKAGE_NAME "/codecs/video/"
1365 diff --git a/src/ekiga-debug-analyser b/src/ekiga-debug-analyser
1366 index f0f680f..10eae4e 100755
1367 --- a/src/ekiga-debug-analyser
1368 +++ b/src/ekiga-debug-analyser
1369 @@ -1,4 +1,4 @@
1370 -#!/usr/bin/awk -f
1371 +#!/usr/bin/gawk -f
1373 # Usage: ekiga-debug-analyser <ekigaDebugOutput
1374 # where the output comes from ekiga -d 4 (or 5).
1375 diff --git a/src/gui/preferences.cpp b/src/gui/preferences.cpp
1376 index 595359c..b715a3c 100644
1377 --- a/src/gui/preferences.cpp
1378 +++ b/src/gui/preferences.cpp
1379 @@ -204,7 +204,8 @@ static void gm_pw_init_audio_codecs_page (GtkWidget *prefs_window,
1380 GtkWidget *container);
1381 static void gm_pw_init_video_codecs_page (GtkWidget *prefs_window,
1382 GtkWidget *container);
1384 +static void gm_pw_init_text_parameter_page (GtkWidget *prefs_window,
1385 + GtkWidget *container);
1388 /* GTK Callbacks */
1389 @@ -945,6 +946,29 @@ gm_pw_init_video_devices_page (GtkWidget *prefs_window,
1393 +static void
1394 +gm_pw_init_text_parameter_page (GtkWidget *prefs_window,
1395 + GtkWidget *container)
1397 + GtkWidget *subsection = NULL;
1398 + GmPreferencesWindow *pw = NULL;
1400 + pw = gm_pw_get_pw (prefs_window);
1402 + /* Here we add text parameter options */
1403 + subsection =
1404 + gnome_prefs_subsection_new (prefs_window, container,
1405 + _("Real time"), 3, 1);
1407 + /* Translators: the full sentence is Automatically adjust jitter buffer
1408 + between X and Y ms */
1409 + gnome_prefs_toggle_new (subsection, _("Enable Realtime"), TEXT_KEY "enable_realtime", _("If enabled, use realtime preview with the chat."), 1);
1411 + gnome_prefs_spin_new (subsection, _("Buffer time (ms):"), TEXT_KEY "buffer_time", _("The buffer size for text reception (in ms)."), 0.0, 2000.0, 1.0, 2, NULL, true);
1413 + // gnome_prefs_spin_new (subsection, _("Max incoming CPS :"), TEXT_KEY "character_per_second", _("The maximum incoming speed for text reception."), 0.0, 2000.0, 1.0, 3, NULL, true);
1417 static void
1418 gm_pw_init_audio_codecs_page (GtkWidget *prefs_window,
1419 @@ -1397,6 +1421,11 @@ gm_prefs_window_new (Ekiga::ServiceCore *core)
1420 gm_pw_init_video_codecs_page (window, container);
1421 gtk_widget_show_all (GTK_WIDGET (container));
1423 + gnome_prefs_window_section_new (window, _("Text"));
1424 + container = gnome_prefs_window_subsection_new (window, _("Text settings"));
1425 + gm_pw_init_text_parameter_page (window, container);
1426 + gtk_widget_show_all (GTK_WIDGET (container));
1429 /* That's an usual GtkWindow, connect it to the signals */
1430 g_signal_connect_swapped (GTK_OBJECT (window),