xref: /haiku/src/kits/interface/InterfaceDefs.cpp (revision cbe35e2031cb2bfb757422f35006bb9bd382bed1)
1 /*
2  * Copyright 2001-2005, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Caz <turok2@currantbun.com>
8  *		Axel Dörfler, axeld@pinc-software.de
9  */
10 
11 /**	Global functions and variables for the Interface Kit */
12 
13 #include <Application.h>
14 #include <Font.h>
15 #include <InterfaceDefs.h>
16 #include <Menu.h>
17 #include <Roster.h>
18 #include <ScrollBar.h>
19 #include <Screen.h>
20 #include <TextView.h>
21 
22 #include <stdlib.h>
23 // TODO: remove this header
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include <AppServerLink.h>
28 #include <WindowInfo.h>
29 #include <InputServerTypes.h>
30 #include <input_globals.h>
31 #include <ServerProtocol.h>
32 #include <WidthBuffer.h>
33 #include <ColorSet.h>	// for private system colors stuff
34 #include <ColorTools.h>
35 
36 #include "moreUTF8.h"
37 #include "truncate_string.h"
38 
39 // Private definitions not placed in public headers
40 void _init_global_fonts_();
41 extern "C" status_t _fini_interface_kit_();
42 
43 using namespace BPrivate;
44 
45 menu_info *_menu_info_ptr_;
46 
47 
48 static status_t
49 mode2parms(uint32 space, uint32 *out_space, int32 *width, int32 *height)
50 {
51 	status_t status = B_OK;
52 
53 	switch (space) {
54 		case B_8_BIT_640x480:
55 			*out_space = B_CMAP8;
56 			*width = 640; *height = 480;
57 			break;
58 		case B_8_BIT_800x600:
59 			*out_space = B_CMAP8;
60 			*width = 800; *height = 600;
61 			break;
62 		case B_8_BIT_1024x768:
63 			*out_space = B_CMAP8;
64 			*width = 1024; *height = 768;
65 			break;
66 		case B_8_BIT_1280x1024:
67 			*out_space = B_CMAP8;
68 			*width = 1280; *height = 1024;
69 			break;
70 		case B_8_BIT_1600x1200:
71 			*out_space = B_CMAP8;
72 			*width = 1600; *height = 1200;
73 			break;
74 		case B_16_BIT_640x480:
75 			*out_space = B_RGB16;
76 			*width = 640; *height = 480;
77 			break;
78 		case B_16_BIT_800x600:
79 			*out_space = B_RGB16;
80 			*width = 800; *height = 600;
81 			break;
82 		case B_16_BIT_1024x768:
83 			*out_space = B_RGB16;
84 			*width = 1024; *height = 768;
85 			break;
86 		case B_16_BIT_1280x1024:
87 			*out_space = B_RGB16;
88 			*width = 1280; *height = 1024;
89 			break;
90 		case B_16_BIT_1600x1200:
91 			*out_space = B_RGB16;
92 			*width = 1600; *height = 1200;
93 			break;
94 		case B_32_BIT_640x480:
95 			*out_space = B_RGB32;
96 			*width = 640; *height = 480;
97 			break;
98 		case B_32_BIT_800x600:
99 			*out_space = B_RGB32;
100 			*width = 800; *height = 600;
101 			break;
102 		case B_32_BIT_1024x768:
103 			*out_space = B_RGB32;
104 			*width = 1024; *height = 768;
105 			break;
106 		case B_32_BIT_1280x1024:
107 			*out_space = B_RGB32;
108 			*width = 1280; *height = 1024;
109 			break;
110 		case B_32_BIT_1600x1200:
111 			*out_space = B_RGB32;
112 			*width = 1600; *height = 1200;
113 			break;
114     		case B_8_BIT_1152x900:
115     			*out_space = B_CMAP8;
116     			*width = 1152; *height = 900;
117     			break;
118     		case B_16_BIT_1152x900:
119     			*out_space = B_RGB16;
120     			*width = 1152; *height = 900;
121     			break;
122     		case B_32_BIT_1152x900:
123     			*out_space = B_RGB32;
124     			*width = 1152; *height = 900;
125     			break;
126 		case B_15_BIT_640x480:
127 			*out_space = B_RGB15;
128 			*width = 640; *height = 480;
129 			break;
130 		case B_15_BIT_800x600:
131 			*out_space = B_RGB15;
132 			*width = 800; *height = 600;
133 			break;
134 		case B_15_BIT_1024x768:
135 			*out_space = B_RGB15;
136 			*width = 1024; *height = 768;
137 			break;
138 		case B_15_BIT_1280x1024:
139 			*out_space = B_RGB15;
140 			*width = 1280; *height = 1024;
141 			break;
142 		case B_15_BIT_1600x1200:
143 			*out_space = B_RGB15;
144 			*width = 1600; *height = 1200;
145 			break;
146     		case B_15_BIT_1152x900:
147     			*out_space = B_RGB15;
148     			*width = 1152; *height = 900;
149     			break;
150     		default:
151     			status = B_BAD_VALUE;
152     			break;
153 	}
154 
155 	return status;
156 }
157 
158 
159 _IMPEXP_BE const color_map *
160 system_colors()
161 {
162 	return BScreen(B_MAIN_SCREEN_ID).ColorMap();
163 }
164 
165 
166 _IMPEXP_BE status_t
167 set_screen_space(int32 index, uint32 space, bool stick)
168 {
169 	int32 width;
170 	int32 height;
171 	uint32 depth;
172 
173 	status_t status = mode2parms(space, &depth, &width, &height);
174 	if (status < B_OK)
175 		return status;
176 
177 	BScreen screen(B_MAIN_SCREEN_ID);
178 	display_mode mode;
179 
180 	// TODO: What about refresh rate ?
181 	// currently we get it from the current video mode, but
182 	// this might be not so wise.
183 	status = screen.GetMode(index, &mode);
184 	if (status < B_OK)
185 		return status;
186 
187 	mode.virtual_width = width;
188 	mode.virtual_height = height;
189 	mode.space = depth;
190 
191 	return screen.SetMode(index, &mode, stick);
192 }
193 
194 
195 _IMPEXP_BE status_t
196 get_scroll_bar_info(scroll_bar_info *info)
197 {
198 	if (info == NULL)
199 		return B_BAD_VALUE;
200 
201 	BPrivate::AppServerLink link;
202 	link.StartMessage(AS_GET_SCROLLBAR_INFO);
203 
204 	int32 code;
205 	if (link.FlushWithReply(code) == B_OK
206 		&& code == B_OK) {
207 		link.Read<scroll_bar_info>(info);
208 		return B_OK;
209 	}
210 
211 	return B_ERROR;
212 }
213 
214 
215 _IMPEXP_BE status_t
216 set_scroll_bar_info(scroll_bar_info *info)
217 {
218 	if (info == NULL)
219 		return B_BAD_VALUE;
220 
221 	BPrivate::AppServerLink link;
222 	int32 code;
223 
224 	link.StartMessage(AS_SET_SCROLLBAR_INFO);
225 	link.Attach<scroll_bar_info>(*info);
226 
227 	if (link.FlushWithReply(code) == B_OK
228 		&& code == B_OK)
229 		return B_OK;
230 
231 	return B_ERROR;
232 }
233 
234 
235 _IMPEXP_BE status_t
236 get_mouse_type(int32 *type)
237 {
238 	BMessage command(IS_GET_MOUSE_TYPE);
239 	BMessage reply;
240 
241 	_control_input_server_(&command, &reply);
242 
243 	if(reply.FindInt32("mouse_type", type) != B_OK)
244 		return B_ERROR;
245 
246 	return B_OK;
247 }
248 
249 
250 _IMPEXP_BE status_t
251 set_mouse_type(int32 type)
252 {
253 	BMessage command(IS_SET_MOUSE_TYPE);
254 	BMessage reply;
255 
256 	command.AddInt32("mouse_type", type);
257 	return _control_input_server_(&command, &reply);
258 }
259 
260 
261 _IMPEXP_BE status_t
262 get_mouse_map(mouse_map *map)
263 {
264 	BMessage command(IS_GET_MOUSE_MAP);
265 	BMessage reply;
266 	const void *data = 0;
267 	ssize_t count;
268 
269 	_control_input_server_(&command, &reply);
270 
271 	if (reply.FindData("mousemap", B_ANY_TYPE, &data, &count) != B_OK)
272 		return B_ERROR;
273 
274 	memcpy(map, data, count);
275 
276 	return B_OK;
277 }
278 
279 
280 _IMPEXP_BE status_t
281 set_mouse_map(mouse_map *map)
282 {
283 	BMessage command(IS_SET_MOUSE_MAP);
284 	BMessage reply;
285 
286 	command.AddData("mousemap", B_ANY_TYPE, map, sizeof(mouse_map));
287 	return _control_input_server_(&command, &reply);
288 }
289 
290 
291 _IMPEXP_BE status_t
292 get_click_speed(bigtime_t *speed)
293 {
294 	BMessage command(IS_GET_CLICK_SPEED);
295 	BMessage reply;
296 
297 	_control_input_server_(&command, &reply);
298 
299 	if (reply.FindInt64("speed", speed) != B_OK)
300 		*speed = 500000;
301 
302 	return B_OK;
303 }
304 
305 
306 _IMPEXP_BE status_t
307 set_click_speed(bigtime_t speed)
308 {
309 	BMessage command(IS_SET_CLICK_SPEED);
310 	BMessage reply;
311 	command.AddInt64("speed", speed);
312 	return _control_input_server_(&command, &reply);
313 }
314 
315 
316 _IMPEXP_BE status_t
317 get_mouse_speed(int32 *speed)
318 {
319 	BMessage command(IS_GET_MOUSE_SPEED);
320 	BMessage reply;
321 
322 	_control_input_server_(&command, &reply);
323 
324 	if (reply.FindInt32("speed", speed) != B_OK)
325 		*speed = 65536;
326 
327 	return B_OK;
328 }
329 
330 
331 _IMPEXP_BE status_t
332 set_mouse_speed(int32 speed)
333 {
334 	BMessage command(IS_SET_MOUSE_SPEED);
335 	BMessage reply;
336 	command.AddInt32("speed", speed);
337 	return _control_input_server_(&command, &reply);
338 }
339 
340 
341 _IMPEXP_BE status_t
342 get_mouse_acceleration(int32 *speed)
343 {
344 	BMessage command(IS_GET_MOUSE_ACCELERATION);
345 	BMessage reply;
346 
347 	_control_input_server_(&command, &reply);
348 
349 	if (reply.FindInt32("speed", speed) != B_OK)
350 		*speed = 65536;
351 
352 	return B_OK;
353 }
354 
355 
356 _IMPEXP_BE status_t
357 set_mouse_acceleration(int32 speed)
358 {
359 	BMessage command(IS_SET_MOUSE_ACCELERATION);
360 	BMessage reply;
361 	command.AddInt32("speed", speed);
362 	return _control_input_server_(&command, &reply);
363 }
364 
365 
366 _IMPEXP_BE status_t
367 get_key_repeat_rate(int32 *rate)
368 {
369 	BMessage command(IS_GET_KEY_REPEAT_RATE);
370 	BMessage reply;
371 
372 	_control_input_server_(&command, &reply);
373 
374 	if (reply.FindInt32("rate", rate) != B_OK)
375 		*rate = 250000;
376 
377 	return B_OK;
378 }
379 
380 
381 _IMPEXP_BE status_t
382 set_key_repeat_rate(int32 rate)
383 {
384 	BMessage command(IS_SET_KEY_REPEAT_RATE);
385 	BMessage reply;
386 	command.AddInt32("rate", rate);
387 	return _control_input_server_(&command, &reply);
388 }
389 
390 
391 _IMPEXP_BE status_t
392 get_key_repeat_delay(bigtime_t *delay)
393 {
394 	BMessage command(IS_GET_KEY_REPEAT_DELAY);
395 	BMessage reply;
396 
397 	_control_input_server_(&command, &reply);
398 
399 	if (reply.FindInt64("delay", delay) != B_OK)
400 		*delay = 200;
401 
402 	return B_OK;
403 }
404 
405 
406 _IMPEXP_BE status_t
407 set_key_repeat_delay(bigtime_t  delay)
408 {
409 	BMessage command(IS_SET_KEY_REPEAT_DELAY);
410 	BMessage reply;
411 	command.AddInt64("delay", delay);
412 	return _control_input_server_(&command, &reply);
413 }
414 
415 
416 _IMPEXP_BE uint32
417 modifiers()
418 {
419 	BMessage command(IS_GET_MODIFIERS);
420 	BMessage reply;
421 	int32 err, modifier;
422 
423 	_control_input_server_(&command, &reply);
424 
425 	if (reply.FindInt32("status", &err) != B_OK)
426 		return 0;
427 
428 	if (reply.FindInt32("modifiers", &modifier) != B_OK)
429 		return 0;
430 
431 	return modifier;
432 }
433 
434 
435 _IMPEXP_BE status_t
436 get_key_info(key_info *info)
437 {
438 	BMessage command(IS_GET_KEY_INFO);
439 	BMessage reply;
440 	const void *data = 0;
441 	int32 err;
442 	ssize_t count;
443 
444 	_control_input_server_(&command, &reply);
445 
446 	if (reply.FindInt32("status", &err) != B_OK)
447 		return B_ERROR;
448 
449 	if (reply.FindData("key_info", B_ANY_TYPE, &data, &count) != B_OK)
450 		return B_ERROR;
451 
452 	memcpy(info, data, count);
453 	return B_OK;
454 }
455 
456 
457 _IMPEXP_BE void
458 get_key_map(key_map **map, char **key_buffer)
459 {
460 	BMessage command(IS_GET_KEY_MAP);
461 	BMessage reply;
462 	ssize_t map_count, key_count;
463 	const void *map_array = 0, *key_array = 0;
464 
465 	_control_input_server_(&command, &reply);
466 
467 	if (reply.FindData("keymap", B_ANY_TYPE, &map_array, &map_count) != B_OK) {
468 		*map = 0; *key_buffer = 0;
469 		return;
470 	}
471 
472 	if (reply.FindData("key_buffer", B_ANY_TYPE, &key_array, &key_count) != B_OK) {
473 		*map = 0; *key_buffer = 0;
474 		return;
475 	}
476 
477 	*map = (key_map *)malloc(map_count);
478 	memcpy(*map, map_array, map_count);
479 	*key_buffer = (char *)malloc(key_count);
480 	memcpy(*key_buffer, key_array, key_count);
481 }
482 
483 
484 _IMPEXP_BE status_t
485 get_keyboard_id(uint16 *id)
486 {
487 	BMessage command(IS_GET_KEYBOARD_ID);
488 	BMessage reply;
489 	uint16 kid;
490 
491 	_control_input_server_(&command, &reply);
492 
493 	reply.FindInt16("id", (int16 *)&kid);
494 	*id = kid;
495 
496 	return B_OK;
497 }
498 
499 
500 _IMPEXP_BE void
501 set_modifier_key(uint32 modifier, uint32 key)
502 {
503 	BMessage command(IS_SET_MODIFIER_KEY);
504 	BMessage reply;
505 
506 	command.AddInt32("modifier", modifier);
507 	command.AddInt32("key", key);
508 	_control_input_server_(&command, &reply);
509 }
510 
511 
512 _IMPEXP_BE void
513 set_keyboard_locks(uint32 modifiers)
514 {
515 	BMessage command(IS_SET_KEYBOARD_LOCKS);
516 	BMessage reply;
517 
518 	command.AddInt32("locks", modifiers);
519 	_control_input_server_(&command, &reply);
520 }
521 
522 
523 _IMPEXP_BE status_t
524 _restore_key_map_()
525 {
526 	BMessage message(IS_RESTORE_KEY_MAP);
527 	BMessage reply;
528 
529 	return _control_input_server_(&message, &reply);
530 }
531 
532 
533 _IMPEXP_BE rgb_color
534 keyboard_navigation_color()
535 {
536 	// Queries the app_server
537 	return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
538 }
539 
540 
541 _IMPEXP_BE int32
542 count_workspaces()
543 {
544 	int32 count = 1;
545 
546 	BPrivate::AppServerLink link;
547 	link.StartMessage(AS_COUNT_WORKSPACES);
548 
549 	status_t status;
550 	if (link.FlushWithReply(status) == B_OK && status == B_OK)
551 		link.Read<int32>(&count);
552 
553 	return count;
554 }
555 
556 
557 _IMPEXP_BE void
558 set_workspace_count(int32 count)
559 {
560 	BPrivate::AppServerLink link;
561 	link.StartMessage(AS_SET_WORKSPACE_COUNT);
562 	link.Attach<int32>(count);
563 	link.Flush();
564 }
565 
566 
567 _IMPEXP_BE int32
568 current_workspace()
569 {
570 	int32 index = 0;
571 
572 	BPrivate::AppServerLink link;
573 	link.StartMessage(AS_CURRENT_WORKSPACE);
574 
575 	int32 status;
576 	if (link.FlushWithReply(status) == B_OK && status == B_OK)
577 		link.Read<int32>(&index);
578 
579 	return index;
580 }
581 
582 
583 _IMPEXP_BE void
584 activate_workspace(int32 workspace)
585 {
586 	BPrivate::AppServerLink link;
587 	link.StartMessage(AS_ACTIVATE_WORKSPACE);
588 	link.Attach<int32>(workspace);
589 	link.Flush();
590 }
591 
592 
593 _IMPEXP_BE bigtime_t
594 idle_time()
595 {
596 	bigtime_t idletime = 0;
597 
598 	BPrivate::AppServerLink link;
599 	link.StartMessage(AS_IDLE_TIME);
600 
601 	int32 code;
602 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
603 		link.Read<int64>(&idletime);
604 
605 	return idletime;
606 }
607 
608 
609 _IMPEXP_BE void
610 run_select_printer_panel()
611 {
612 	// Launches the Printer prefs app via the Roster
613 	be_roster->Launch("application/x-vnd.Be-PRNT");
614 }
615 
616 
617 _IMPEXP_BE void
618 run_add_printer_panel()
619 {
620 	// Launches the Printer prefs app via the Roster and asks it to
621 	// add a printer
622 	// TODO: Implement
623 }
624 
625 
626 _IMPEXP_BE void
627 run_be_about()
628 {
629 	if (be_roster != NULL)
630 		be_roster->Launch("application/x-vnd.haiku-AboutHaiku");
631 }
632 
633 
634 _IMPEXP_BE void
635 set_focus_follows_mouse(bool follow)
636 {
637 	// obviously deprecated API
638 	set_mouse_mode(B_WARP_MOUSE);
639 }
640 
641 
642 _IMPEXP_BE bool
643 focus_follows_mouse()
644 {
645 	return mouse_mode() != B_NORMAL_MOUSE;
646 }
647 
648 
649 _IMPEXP_BE void
650 set_mouse_mode(mode_mouse mode)
651 {
652 	BPrivate::AppServerLink link;
653 	link.StartMessage(AS_SET_MOUSE_MODE);
654 	link.Attach<mode_mouse>(mode);
655 	link.Flush();
656 }
657 
658 
659 _IMPEXP_BE mode_mouse
660 mouse_mode()
661 {
662 	// Gets the focus-follows-mouse style, such as normal, B_WARP_MOUSE, etc.
663 	mode_mouse mode = B_NORMAL_MOUSE;
664 
665 	BPrivate::AppServerLink link;
666 	link.StartMessage(AS_GET_MOUSE_MODE);
667 
668 	int32 code;
669 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
670 		link.Read<mode_mouse>(&mode);
671 
672 	return mode;
673 }
674 
675 
676 _IMPEXP_BE rgb_color
677 ui_color(color_which which)
678 {
679 	if (!be_app) {
680 			switch (which) {
681 				case B_PANEL_BACKGROUND_COLOR:
682 					return make_color(216,216,216);
683 				case B_PANEL_TEXT_COLOR:
684 					return make_color(0,0,0);
685 				case B_DOCUMENT_BACKGROUND_COLOR:
686 					return make_color(255,255,255);
687 				case B_DOCUMENT_TEXT_COLOR:
688 					return make_color(0,0,0);
689 				case B_CONTROL_BACKGROUND_COLOR:
690 					return make_color(245,245,245);
691 				case B_CONTROL_TEXT_COLOR:
692 					return make_color(0,0,0);
693 				case B_CONTROL_BORDER_COLOR:
694 					return make_color(0,0,0);
695 				case B_CONTROL_HIGHLIGHT_COLOR:
696 					return make_color(102, 152, 203);
697 				case B_NAVIGATION_BASE_COLOR:
698 					return make_color(0,0,229);
699 				case B_NAVIGATION_PULSE_COLOR:
700 					return make_color(0,0,0);
701 				case B_SHINE_COLOR:
702 					return make_color(255,255,255);
703 				case B_SHADOW_COLOR:
704 					return make_color(0,0,0);
705 				case B_MENU_BACKGROUND_COLOR:
706 					return make_color(216,216,216);
707 				case B_MENU_SELECTED_BACKGROUND_COLOR:
708 					return make_color(115,120,184);
709 				case B_MENU_ITEM_TEXT_COLOR:
710 					return make_color(0,0,0);
711 				case B_MENU_SELECTED_BORDER_COLOR:
712 					return make_color(0,0,0);
713 				case B_TOOLTIP_BACKGROUND_COLOR:
714 					return make_color(255,255,0);
715 				case B_TOOLTIP_TEXT_COLOR:
716 					return make_color(0,0,0);
717 				case B_SUCCESS_COLOR:
718 					return make_color(0,255,0);
719 				case B_FAILURE_COLOR:
720 					return make_color(255,0,0);
721 				default:
722 					fprintf(stderr, "ui_color(): unknown color_which\n");
723 					return make_color(0,0,0);
724 			}
725 	}
726 
727 	rgb_color color;
728 	BPrivate::AppServerLink link;
729 	link.StartMessage(AS_GET_UI_COLOR);
730 	link.Attach<color_which>(which);
731 
732 	int32 code;
733 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
734 		link.Read<rgb_color>(&color);
735 
736 	return color;
737 }
738 
739 
740 _IMPEXP_BE rgb_color
741 tint_color(rgb_color color, float tint)
742 {
743 	rgb_color result;
744 
745 	#define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint))
746 	#define DARKEN(x)  ((uint8)(x * (2 - tint)))
747 
748 	if (tint < 1.0f) {
749 		result.red   = LIGHTEN(color.red);
750 		result.green = LIGHTEN(color.green);
751 		result.blue  = LIGHTEN(color.blue);
752 		result.alpha = color.alpha;
753 	} else {
754 		result.red   = DARKEN(color.red);
755 		result.green = DARKEN(color.green);
756 		result.blue  = DARKEN(color.blue);
757 		result.alpha = color.alpha;
758 	}
759 
760 	#undef LIGHTEN
761 	#undef DARKEN
762 
763 	return result;
764 }
765 
766 
767 static status_t
768 load_menu_settings(menu_info &into)
769 {
770 	// TODO: Load settings from the settings file,
771 	// and only if it fails, fallback to the defaults
772 
773 	// TODO: shouldn't the server handle the details? It could broadcast
774 	//	change messages to the applications, which could also relayout
775 	//	there menus and menu bars then (as soon as we have a layout management)
776 	into.font_size = be_plain_font->Size();
777 	be_plain_font->GetFamilyAndStyle(&into.f_family, &into.f_style);
778 	into.background_color = ui_color(B_MENU_BACKGROUND_COLOR);
779 	into.separator = 0;
780 	into.click_to_open = true;
781 	into.triggers_always_shown = false;
782 
783 	return B_OK;
784 }
785 
786 
787 extern "C" status_t
788 _init_interface_kit_()
789 {
790 	sem_id widthSem = create_sem(0, "BTextView WidthBuffer Sem");
791 	if (widthSem < 0)
792 		return widthSem;
793 	BTextView::sWidthSem = widthSem;
794 	BTextView::sWidthAtom = 0;
795 	BTextView::sWidths = new _BWidthBuffer_;
796 
797 	_init_global_fonts_();
798 
799 	_menu_info_ptr_ = &BMenu::sMenuInfo;
800 	status_t status = load_menu_settings(BMenu::sMenuInfo);
801 
802 	// TODO: fill the other static members
803 
804 	return status;
805 }
806 
807 
808 extern "C" status_t
809 _fini_interface_kit_()
810 {
811 	//TODO: Implement ?
812 
813 	return B_OK;
814 }
815 
816 
817 //	#pragma mark -
818 
819 
820 /*!
821 	\brief private function used by Deskbar to set window decor
822 	Note, we don't have to be compatible here, and could just change
823 	the Deskbar not to use this anymore
824 	\param theme The theme to choose
825 
826 	- \c 0: BeOS
827 	- \c 1: AmigaOS
828 	- \c 2: Win95
829 	- \c 3: MacOS
830 */
831 void
832 __set_window_decor(int32 theme)
833 {
834 	BPrivate::AppServerLink link;
835 	link.StartMessage(AS_R5_SET_DECORATOR);
836 	link.Attach<int32>(theme);
837 	link.Flush();
838 }
839 
840 namespace BPrivate {
841 
842 /*!
843 	\brief queries the server for the number of available decorators
844 	\return the number of available decorators
845 */
846 int32
847 count_decorators(void)
848 {
849 	BPrivate::AppServerLink link;
850 	link.StartMessage(AS_COUNT_DECORATORS);
851 
852 	int32 code;
853 	int32 count = -1;
854 	if (link.FlushWithReply(code) == B_OK)
855 		link.Read<int32>(&count);
856 
857 	return count;
858 }
859 
860 /*!
861 	\brief queries the server for the index of the current decorators
862 	\return the current decorator's index
863 
864 	If for some bizarre reason this function fails, it returns -1
865 */
866 int32
867 get_decorator(void)
868 {
869 	BPrivate::AppServerLink link;
870 	link.StartMessage(AS_GET_DECORATOR);
871 
872 	int32 code;
873 	int32 index = -1;
874 	if (link.FlushWithReply(code) == B_OK)
875 		link.Read<int32>(&index);
876 
877 	return index;
878 }
879 
880 
881 /*!
882 	\brief queries the server for the name of the decorator with a certain index
883 	\param index The index of the decorator to get the name for
884 	\param name BString to receive the name of the decorator
885 	\return B_OK if successful, B_ERROR if not
886 */
887 status_t
888 get_decorator_name(const int32 &index, BString &name)
889 {
890 	BPrivate::AppServerLink link;
891 	int32 code;
892 
893 	link.StartMessage(AS_GET_DECORATOR_NAME);
894 	link.Attach<int32>(index);
895 
896 	if (link.FlushWithReply(code) == B_OK)
897 	{
898 		char *string;
899 		if(link.ReadString(&string)==B_OK)
900 		{
901 			name=string;
902 			delete [] string;
903 			return B_OK;
904 		}
905 	}
906 
907 	return B_ERROR;
908 }
909 
910 /*!
911 	\brief asks the server to draw a decorator preview into a BBitmap
912 	\param index The index of the decorator to get the name for
913 	\param bitmap BBitmap to receive the preview
914 	\return B_OK if successful, B_ERROR if not.
915 
916 	This is currently unimplemented.
917 */
918 status_t
919 get_decorator_preview(const int32 &index, BBitmap *bitmap)
920 {
921 	// TODO: implement get_decorator_preview
922 	return B_ERROR;
923 }
924 
925 
926 /*!
927 	\brief Private function which sets the window decorator for the system.
928 	\param index Index of the decorator to set
929 
930 	If the index is invalid, this function and the server do nothing
931 */
932 status_t
933 set_decorator(const int32 &index)
934 {
935 	if(index < 0)
936 		return B_BAD_VALUE;
937 
938 	BPrivate::AppServerLink link;
939 
940 	link.StartMessage(AS_SET_DECORATOR);
941 	link.Attach<int32>(index);
942 	link.Flush();
943 
944 	return B_OK;
945 }
946 
947 /*!
948 	\brief Private function to get the system's GUI colors as a set
949 	\param colors The recipient color set
950 */
951 void
952 get_system_colors(ColorSet *colors)
953 {
954 	if (!colors)
955 		return;
956 
957 	BPrivate::AppServerLink link;
958 	link.StartMessage(AS_GET_UI_COLORS);
959 
960 	int32 code;
961 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
962 		link.Read<ColorSet>(colors);
963 }
964 
965 /*!
966 	\brief Private function to set the system's GUI colors all at once
967 	\param colors The color set to use
968 */
969 void
970 set_system_colors(const ColorSet &colors)
971 {
972 	BPrivate::AppServerLink link;
973 
974 	link.StartMessage(AS_SET_UI_COLORS);
975 	link.Attach<ColorSet>(colors);
976 	link.Flush();
977 }
978 
979 }	// namespace BPrivate
980 
981 // These methods were marked with "Danger, will Robinson!" in
982 // the OpenTracker source, so we might not want to be compatible
983 // here.
984 // In any way, we would need to update Deskbar to use our
985 // replacements, so we could as well just implement them...
986 //
987 // They are defined (also the complete window_info structure) in
988 // src/apps/deskbar/WindowMenuItem.h
989 
990 struct window_info;
991 
992 void do_window_action(int32 window_id, int32 action,
993 		BRect zoomRect, bool zoom);
994 window_info	*get_window_info(int32 a_token);
995 int32 *get_token_list(team_id app, int32 *count);
996 void do_bring_to_front_team(BRect zoomRect, team_id app, bool zoom);
997 void do_minimize_team(BRect zoomRect, team_id team, bool zoom);
998 
999 
1000 void
1001 do_window_action(int32 window_id, int32 action,
1002 	BRect zoomRect, bool zoom)
1003 {
1004 	// ToDo: implement me, needed for Deskbar!
1005 }
1006 
1007 
1008 window_info	*
1009 get_window_info(int32 serverToken)
1010 {
1011 	BPrivate::AppServerLink link;
1012 
1013 	link.StartMessage(AS_GET_WINDOW_INFO);
1014 	link.Attach<int32>(serverToken);
1015 
1016 	int32 code;
1017 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1018 		return NULL;
1019 
1020 	int32 size;
1021 	link.Read<int32>(&size);
1022 
1023 	client_window_info* info = (client_window_info*)malloc(size);
1024 	if (info == NULL)
1025 		return NULL;
1026 
1027 	link.Read(info, size);
1028 	return info;
1029 }
1030 
1031 
1032 int32 *
1033 get_token_list(team_id team, int32 *_count)
1034 {
1035 	BPrivate::AppServerLink link;
1036 
1037 	link.StartMessage(AS_GET_WINDOW_LIST);
1038 	link.Attach<team_id>(team);
1039 
1040 	int32 code;
1041 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1042 		return NULL;
1043 
1044 	int32 count;
1045 	link.Read<int32>(&count);
1046 
1047 	int32* tokens = (int32*)malloc(count * sizeof(int32));
1048 	if (tokens == NULL)
1049 		return NULL;
1050 
1051 	link.Read(tokens, count * sizeof(int32));
1052 	*_count = count;
1053 	return tokens;
1054 }
1055 
1056 
1057 void
1058 do_bring_to_front_team(BRect zoomRect, team_id app, bool zoom)
1059 {
1060 	// ToDo: implement me, needed for Deskbar!
1061 }
1062 
1063 
1064 void
1065 do_minimize_team(BRect zoomRect, team_id team, bool zoom)
1066 {
1067 	// ToDo: implement me, needed for Deskbar!
1068 }
1069 
1070 
1071 //	#pragma mark - truncate string
1072 
1073 
1074 static char*
1075 write_ellipsis(char* dst)
1076 {
1077 	strcpy(dst, B_UTF8_ELLIPSIS);
1078 	// The UTF-8 character spans over 3 bytes
1079 	return dst + 3;
1080 }
1081 
1082 
1083 bool
1084 truncate_end(const char* source, char* dest, uint32 numChars,
1085 	const float* escapementArray, float width, float ellipsisWidth, float size)
1086 {
1087 	float currentWidth = 0.0;
1088 	ellipsisWidth /= size;	// test if this is as accurate as escapementArray * size
1089 	width /= size;
1090 	uint32 lastFit = 0, c;
1091 
1092 	for (c = 0; c < numChars; c++) {
1093 		currentWidth += escapementArray[c];
1094 		if (currentWidth + ellipsisWidth <= width)
1095 			lastFit = c;
1096 
1097 		if (currentWidth > width)
1098 			break;
1099 	}
1100 
1101 	if (c == numChars) {
1102 		// string fits into width
1103 		return false;
1104 	}
1105 
1106 	if (c == 0) {
1107 		// there is no space for the ellipsis
1108 		strcpy(dest, "");
1109 		return true;
1110 	}
1111 
1112 	// copy string to destination
1113 
1114 	for (uint32 i = 0; i < lastFit + 1; i++) {
1115 		// copy one glyph
1116 		do {
1117 			*dest++ = *source++;
1118 		} while (IsInsideGlyph(*source));
1119 	}
1120 
1121 	// write ellipsis and terminate
1122 
1123 	dest = write_ellipsis(dest);
1124 	*dest = '\0';
1125 	return true;
1126 }
1127 
1128 
1129 static char*
1130 copy_from_end(const char* src, char* dst, uint32 numChars, uint32 length,
1131 	const float* escapementArray, float width, float ellipsisWidth, float size)
1132 {
1133 	const char* originalStart = src;
1134 	src += length - 1;
1135 	float currentWidth = 0.0;
1136 	for (int32 c = numChars - 1; c > 0; c--) {
1137 		currentWidth += escapementArray[c] * size;
1138 		if (currentWidth > width) {
1139 			// ups, we definitely don't fit. go back until the ellipsis fits
1140 			currentWidth += ellipsisWidth;
1141 			// go forward again until ellipsis fits (already beyond the target)
1142 			for (uint32 c2 = c; c2 < numChars; c2++) {
1143 //printf(" backward: %c (%ld) (%.1f - %.1f = %.1f)\n", *dst, c2, currentWidth, escapementArray[c2] * size, currentWidth - escapementArray[c2] * size);
1144 				currentWidth -= escapementArray[c2] * size;
1145 				do {
1146 					src++;
1147 				} while (IsInsideGlyph(*src));
1148 				// see if we went back enough
1149 				if (currentWidth <= width)
1150 					break;
1151 			}
1152 			break;
1153 		} else {
1154 			// go back one glyph
1155 			do {
1156 				src--;
1157 			} while (IsInsideGlyph(*src));
1158 		}
1159 	}
1160 	// copy from the end of the string
1161 	uint32 bytesToCopy = originalStart + length - src;
1162 	memcpy(dst, src, bytesToCopy);
1163 	dst += bytesToCopy;
1164 	return dst;
1165 }
1166 
1167 
1168 bool
1169 truncate_middle(const char* source, char* dest, uint32 numChars,
1170 	const float* escapementArray, float width, float ellipsisWidth, float size)
1171 {
1172 	// find visual center
1173 
1174 	ellipsisWidth /= size;	// test if this is as accurate as escapementArray * size
1175 	width /= size;
1176 
1177 	float halfWidth = (width - ellipsisWidth) / 2.0;
1178 	float leftWidth = 0.0, rightWidth = 0.0;
1179 	uint32 left, right;
1180 
1181 	// coming from left...
1182 
1183 	for (left = 0; left < numChars; left++) {
1184 		if (leftWidth + escapementArray[left] > halfWidth)
1185 			break;
1186 
1187 		leftWidth += escapementArray[left];
1188 	}
1189 
1190 	if (left == numChars) {
1191 		// string is smaller than half of the maximum width
1192 		return false;
1193 	}
1194 
1195 	// coming from right...
1196 
1197 	for (right = numChars; right-- > left; ) {
1198 		if (rightWidth + escapementArray[right] > halfWidth)
1199 			break;
1200 
1201 		rightWidth += escapementArray[right];
1202 	}
1203 
1204 	if (left >= right) {
1205 		// string is smaller than the maximum width
1206 		return false;
1207 	}
1208 
1209 	if (left == 0 || right >= numChars - 1) {
1210 		// there is no space for the ellipsis
1211 		strcpy(dest, "");
1212 		return true;
1213 	}
1214 
1215 	// see if the gap between left/right is smaller than the ellipsis
1216 
1217 	float totalWidth = rightWidth + leftWidth;
1218 
1219 	for (uint32 i = left; i < right; i++) {
1220 		totalWidth += escapementArray[i];
1221 		if (totalWidth > width)
1222 			break;
1223 	}
1224 
1225 	if (totalWidth <= width) {
1226 		// the whole string fits!
1227 		return false;
1228 	}
1229 
1230 	// The ellipsis now definitely fits, but let's
1231 	// see if we can add another character
1232 
1233 	totalWidth = ellipsisWidth + rightWidth + leftWidth;
1234 
1235 	if (left > numChars - right) {
1236 		// try right letter first
1237 		if (escapementArray[right] + totalWidth <= width)
1238 			right--;
1239 		else if (escapementArray[left] + totalWidth <= width)
1240 			left++;
1241 	} else {
1242 		// try left letter first
1243 		if (escapementArray[left] + totalWidth <= width)
1244 			left++;
1245 		else if (escapementArray[right] + totalWidth <= width)
1246 			right--;
1247 	}
1248 
1249 	// copy characters
1250 
1251 	for (uint32 i = 0; i < left; i++) {
1252 		// copy one glyph
1253 		do {
1254 			*dest++ = *source++;
1255 		} while (IsInsideGlyph(*source));
1256 	}
1257 
1258 	dest = write_ellipsis(dest);
1259 
1260 	for (uint32 i = left; i < numChars; i++) {
1261 		// copy one glyph
1262 		do {
1263 			if (i >= right)
1264 				*dest++ = *source++;
1265 			else
1266 				source++;
1267 		} while (IsInsideGlyph(*source));
1268 	}
1269 
1270 	// terminate
1271 	dest[0] = '\0';
1272 	return true;
1273 }
1274 
1275 
1276 // ToDo: put into BPrivate namespace
1277 void
1278 truncate_string(const char* string, uint32 mode, float width,
1279 	char* result, const float* escapementArray, float fontSize,
1280 	float ellipsisWidth, int32 length, int32 numChars)
1281 {
1282 	// ToDo: that's actually not correct: the string could be smaller than ellipsisWidth
1283 	if (string == NULL /*|| width < ellipsisWidth*/) {
1284 		// we don't have room for a single glyph
1285 		strcpy(result, "");
1286 		return;
1287 	}
1288 
1289 	// iterate over glyphs and copy source into result string
1290 	// one glyph at a time as long as we have room for the "…" yet
1291 	char* dest = result;
1292 	const char* source = string;
1293 	bool truncated = true;
1294 
1295 	switch (mode) {
1296 		case B_TRUNCATE_BEGINNING: {
1297 			dest = copy_from_end(source, dest, numChars, length,
1298 				escapementArray, width, ellipsisWidth, fontSize);
1299 			// "dst" points to the position behind the last glyph that
1300 			// was copied.
1301 			int32 dist = dest - result;
1302 			// we didn't terminate yet
1303 			*dest = 0;
1304 			if (dist < length) {
1305 				// TODO: Is there a smarter way?
1306 				char* temp = new char[dist + 4];
1307 				char* t = temp;
1308 				// append "…"
1309 				t = write_ellipsis(t);
1310 				// shuffle arround strings so that "…" is prepended
1311 				strcpy(t, result);
1312 				strcpy(result, temp);
1313 				delete[] temp;
1314 /*						char t = result[3];
1315 				memmove(&result[3], result, dist + 1);
1316 				write_ellipsis(result);
1317 				result[3] = t;*/
1318 			}
1319 			break;
1320 		}
1321 
1322 		case B_TRUNCATE_END:
1323 			truncated = truncate_end(source, dest, numChars, escapementArray,
1324 				width, ellipsisWidth, fontSize);
1325 			break;
1326 
1327 		case B_TRUNCATE_SMART:
1328 			// TODO: implement, though it was never implemented on R5
1329 			// FALL THROUGH (at least do something)
1330 		case B_TRUNCATE_MIDDLE:
1331 			truncated = truncate_middle(source, dest, numChars, escapementArray,
1332 				width, ellipsisWidth, fontSize);
1333 			break;
1334 	}
1335 
1336 	if (!truncated) {
1337 		// copy string to destination verbatim
1338 		strlcpy(dest, source, length + 1);
1339 	}
1340 }
1341 
1342