Mercurial > hg > xemacs-beta
annotate src/balloon_help.c @ 5712:bee2e2568828 r21-5-33
XEmacs 21.5.33 "horseradish" is released.
| author | Stephen J. Turnbull <stephen@xemacs.org> |
|---|---|
| date | Sat, 05 Jan 2013 02:11:22 +0900 |
| parents | 308d34e9f07d |
| children |
| rev | line source |
|---|---|
| 428 | 1 /* Balloon Help |
| 2 Copyright (c) 1997 Douglas Keller | |
| 3 | |
| 4 This file is part of XEmacs. | |
| 5 | |
|
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2286
diff
changeset
|
6 XEmacs is free software: you can redistribute it and/or modify it |
| 428 | 7 under the terms of the GNU General Public License as published by the |
|
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2286
diff
changeset
|
8 Free Software Foundation, either version 3 of the License, or (at your |
|
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2286
diff
changeset
|
9 option) any later version. |
| 428 | 10 |
| 11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
| 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 14 for more details. | |
| 15 | |
| 16 You should have received a copy of the GNU General Public License | |
|
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
2286
diff
changeset
|
17 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
| 428 | 18 |
| 19 /* Synched up with: Not in FSF. */ | |
| 20 | |
| 771 | 21 /* !!#### Needs to be Mule-ized. */ |
| 22 | |
| 428 | 23 /* |
| 24 * Balloon Help | |
| 25 * | |
| 26 * Version: 1.337 (Sun Apr 13 04:52:10 1997) | |
| 27 * | |
| 28 * Written by Douglas Keller <dkeller@vnet.ibm.com> | |
| 29 * | |
| 30 * | |
| 31 */ | |
| 32 | |
| 33 #include <config.h> | |
| 34 #include <string.h> | |
| 35 #include <stdlib.h> | |
| 36 #include <stdio.h> | |
| 37 #include <assert.h> | |
| 38 | |
| 39 #include <X11/Xlib.h> | |
| 40 #include <X11/Xutil.h> | |
| 41 #include <X11/extensions/shape.h> | |
| 42 | |
| 2286 | 43 #include "compiler.h" |
| 428 | 44 #include "xintrinsic.h" |
| 45 | |
| 46 #include "balloon_help.h" | |
| 47 | |
| 442 | 48 #ifndef max |
| 428 | 49 #define max(x,y) (x>y?x:y) |
| 50 #endif | |
| 51 | |
| 52 #undef bool | |
| 53 #define bool int | |
| 54 | |
| 55 #define MARGIN_WIDTH 4 | |
| 56 #define POINTER_OFFSET 8 | |
| 57 #define BORDER_WIDTH 2 | |
| 58 #define BORDER_WIDTH_HALF 1 | |
| 59 | |
| 60 #define CONE_HEIGHT 20 | |
| 61 #define CONE_WIDTH 50 | |
| 62 | |
| 63 #define SHAPE_CONE_TOP (1<<0) | |
| 64 #define SHAPE_CONE_LEFT (1<<1) | |
| 65 #define SHAPE_CONE_TOP_LEFT (SHAPE_CONE_TOP | SHAPE_CONE_LEFT) | |
| 66 #define SHAPE_CONE_TOP_RIGHT (SHAPE_CONE_TOP) | |
| 67 #define SHAPE_CONE_BOTTOM_LEFT (SHAPE_CONE_LEFT) | |
| 68 #define SHAPE_CONE_BOTTOM_RIGHT (0) | |
| 69 #define SHAPE_CONE_FREE (-1) | |
| 70 | |
| 71 | |
| 72 static Display* b_dpy; | |
| 73 | |
| 74 static XFontStruct* b_fontStruct; | |
| 75 static GC b_gc; | |
| 76 | |
| 77 static GC b_shineGC; | |
| 78 static GC b_shadowGC; | |
| 79 | |
| 80 static Window b_win; | |
| 81 static bool b_winMapped; | |
| 82 | |
| 83 static Pixmap b_mask; | |
| 84 static int b_maskWidth, b_maskHeight; | |
| 85 static GC b_maskGC; | |
| 86 | |
| 442 | 87 static const char* b_text; |
| 428 | 88 static int b_width, b_height; |
| 89 | |
| 90 static XtIntervalId b_timer; | |
| 91 static unsigned long b_delay; | |
| 92 | |
| 93 static int b_screenWidth, b_screenHeight; | |
| 94 | |
| 95 static int b_lastShape; | |
| 96 | |
| 97 /*============================================================================ | |
| 98 | |
| 99 ============================================================================*/ | |
| 100 | |
| 101 static GC | |
| 102 create_gc (Display* dpy, Window win, unsigned long fg, unsigned long bg, | |
| 103 XFontStruct* fontStruct) | |
| 104 { | |
| 105 XGCValues gcv; | |
| 106 unsigned long mask; | |
| 107 | |
| 108 gcv.foreground = fg; | |
| 109 gcv.background = bg; | |
| 110 gcv.font = fontStruct->fid; | |
| 111 gcv.join_style = JoinMiter; | |
| 112 gcv.line_width = BORDER_WIDTH; | |
| 113 | |
| 114 mask = GCFont | GCBackground | GCForeground | GCJoinStyle | GCLineWidth; | |
| 115 | |
| 116 return XCreateGC (dpy, win, mask, &gcv); | |
| 117 } | |
| 118 | |
| 119 static void | |
| 120 destroy_gc (Display* dpy, GC gc) | |
| 121 { | |
| 122 if (gc) | |
| 123 { | |
| 124 XFreeGC (dpy, gc); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 /*============================================================================ | |
| 129 | |
| 130 ============================================================================*/ | |
| 131 | |
| 132 static Window | |
| 133 create_window (Display* dpy, unsigned long bg) | |
| 134 { | |
| 135 Window win; | |
| 136 XSetWindowAttributes attr; | |
| 137 unsigned long attr_mask; | |
| 138 | |
| 139 attr_mask = CWOverrideRedirect | CWBackPixel | CWSaveUnder; | |
| 140 attr.override_redirect = True; | |
| 141 attr.background_pixel = bg; | |
| 142 attr.save_under = True; | |
| 143 | |
| 144 win = | |
| 145 XCreateWindow (dpy, | |
| 146 DefaultRootWindow (dpy), | |
| 147 0, 0, 1, 1, | |
| 148 0, | |
| 149 CopyFromParent, InputOutput, CopyFromParent, | |
| 150 attr_mask, &attr); | |
| 151 | |
| 152 XSelectInput (dpy, win, | |
| 153 SubstructureRedirectMask | | |
| 154 SubstructureNotifyMask | | |
| 155 ExposureMask | | |
| 156 EnterWindowMask | | |
| 157 LeaveWindowMask); | |
| 158 return win; | |
| 159 } | |
| 160 | |
| 161 static void | |
| 162 destroy_window (Display* dpy, Window win) | |
| 163 { | |
| 164 if (win) | |
| 165 { | |
| 166 XDestroyWindow (dpy, win); | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 /*============================================================================ | |
| 171 | |
| 172 ============================================================================*/ | |
| 173 | |
| 174 static void | |
| 175 get_pointer_xy (Display* dpy, int* x_return, int* y_return) | |
| 176 { | |
| 177 int dummy; | |
| 178 unsigned int mask; | |
| 179 Window dummy_win; | |
| 180 | |
| 181 XQueryPointer (dpy, RootWindow(dpy, DefaultScreen(dpy)), &dummy_win, &dummy_win, | |
| 182 x_return, y_return, &dummy, &dummy, &mask); | |
| 183 } | |
| 184 | |
| 185 /*============================================================================ | |
| 186 | |
| 187 ============================================================================*/ | |
| 188 | |
| 189 static void | |
| 190 create_pixmap_mask (int width, int height) | |
| 191 { | |
| 192 b_maskWidth = width; | |
| 193 b_maskHeight = height; | |
| 194 b_mask = XCreatePixmap (b_dpy, b_win, width, height, 1); | |
| 195 } | |
| 196 | |
| 197 static void | |
| 198 destroy_pixmap_mask(void) | |
| 199 { | |
| 200 XFreePixmap (b_dpy, b_mask); | |
| 201 } | |
| 202 | |
| 203 static void | |
| 204 grow_pixmap_mask (int width, int height) | |
| 205 { | |
| 206 if (width > b_maskWidth || height > b_maskHeight) | |
| 207 { | |
| 208 destroy_pixmap_mask (); | |
| 209 create_pixmap_mask (width, height); | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 /*============================================================================ | |
| 214 | |
| 215 ============================================================================*/ | |
| 216 | |
| 217 static void | |
| 442 | 218 text_extent (XFontStruct* fontStruct, const char* text, int len, |
| 428 | 219 int* width, int* height) |
| 220 { | |
| 221 XCharStruct extent; | |
| 222 int dummy; | |
| 223 | |
| 224 XTextExtents (fontStruct, text, len, &dummy, &dummy, &dummy, &extent); | |
| 225 | |
| 226 *width = extent.width; | |
| 227 *height = fontStruct->ascent + fontStruct->descent; | |
| 228 } | |
| 229 | |
| 230 static void | |
| 2286 | 231 get_text_size (Display* UNUSED (dpy), XFontStruct* fontStruct, |
| 232 const char* text, int* max_width, int* max_height) | |
| 428 | 233 { |
| 234 int width; | |
| 235 int height; | |
| 442 | 236 const char* start; |
| 237 const char* end; | |
| 428 | 238 |
| 239 *max_width = *max_height = 0; | |
| 240 | |
| 241 start = text; | |
| 242 while ((end = strchr(start, '\n'))) | |
| 243 { | |
| 244 text_extent (fontStruct, start, end - start, &width, &height); | |
| 245 *max_width = max (width, *max_width); | |
| 246 *max_height += height; | |
| 247 | |
| 248 start = end + 1; | |
| 249 } | |
| 250 text_extent (fontStruct, start, strlen (start), &width, &height); | |
| 251 *max_width = max (width, *max_width); | |
| 252 *max_height += height; | |
| 253 | |
| 254 /* Min width */ | |
| 255 *max_width = max (*max_width, CONE_WIDTH / 2 * 3); | |
| 256 | |
| 257 } | |
| 258 | |
| 259 static void | |
| 260 draw_text (Display* dpy, Window win, GC gc, XFontStruct* fontStruct, | |
| 442 | 261 int x, int y, const char* text) |
| 428 | 262 { |
| 442 | 263 const char* start; |
| 264 const char* end; | |
| 428 | 265 int font_height; |
| 266 | |
| 267 y += fontStruct->ascent; | |
| 268 | |
| 269 font_height = fontStruct->ascent + fontStruct->descent; | |
| 270 | |
| 271 start = text; | |
| 272 while ((end = strchr(start, '\n'))) | |
| 273 { | |
| 274 XDrawString (dpy, win, gc, x, y, start, end - start); | |
| 275 | |
| 276 start = end + 1; | |
| 277 y += font_height; | |
| 278 } | |
| 279 XDrawString (dpy, win, gc, x, y, start, strlen (start)); | |
| 280 } | |
| 281 | |
| 282 /*============================================================================ | |
| 283 | |
| 284 ============================================================================*/ | |
| 285 | |
| 286 static int | |
| 287 get_shape (int last_shape, int x, int y, int width, int height, | |
| 288 int screen_width, int screen_height) | |
| 289 { | |
| 290 /* Can we use last_shape? */ | |
| 291 if (((last_shape == SHAPE_CONE_TOP_LEFT) && | |
| 292 (x + width < screen_width) && (y + height < screen_height)) || | |
| 293 ((last_shape == SHAPE_CONE_TOP_RIGHT) && | |
| 294 (x - width > 0) && (y + height < screen_height)) || | |
| 295 ((last_shape == SHAPE_CONE_BOTTOM_LEFT) && | |
| 296 (x + width < screen_width) && (y - height > 0)) || | |
| 297 ((last_shape == SHAPE_CONE_BOTTOM_RIGHT) && | |
| 298 (x - width > 0) && (y - height > 0))) | |
| 299 return last_shape; | |
| 300 | |
| 301 /* Try to pick a shape that will not get changed, | |
| 302 e.g. if top left quadrant, top_left */ | |
| 303 return (x < screen_width / 2) ? | |
| 304 (y < screen_height / 2 ? SHAPE_CONE_TOP_LEFT: SHAPE_CONE_BOTTOM_LEFT) : | |
| 305 (y < screen_height / 2 ? SHAPE_CONE_TOP_RIGHT: SHAPE_CONE_BOTTOM_RIGHT); | |
| 306 } | |
| 307 | |
| 308 static void | |
| 2286 | 309 make_mask (int shape, int UNUSED (x), int UNUSED (y), int width, int height) |
| 428 | 310 { |
| 311 XPoint cone[ 3 ]; | |
| 312 | |
| 313 grow_pixmap_mask (width, height); | |
| 314 | |
| 315 /* Clear mask */ | |
| 316 XSetForeground (b_dpy, b_maskGC, 0); | |
| 317 XFillRectangle (b_dpy, b_mask, b_maskGC, | |
| 318 0, 0, width, height); | |
| 319 | |
| 320 /* Enable text area */ | |
| 321 XSetForeground (b_dpy, b_maskGC, 1); | |
| 322 XFillRectangle (b_dpy, b_mask, b_maskGC, 0, | |
| 323 shape & SHAPE_CONE_TOP ? CONE_HEIGHT : 0, width, height - CONE_HEIGHT); | |
| 324 | |
| 325 /* Enable for cone area */ | |
| 326 cone[0].x = (shape & SHAPE_CONE_LEFT) ? CONE_WIDTH / 2 : width - (CONE_WIDTH / 2); | |
| 327 cone[0].y = (shape & SHAPE_CONE_TOP) ? CONE_HEIGHT : height - CONE_HEIGHT; | |
| 328 cone[1].x = (shape & SHAPE_CONE_LEFT) ? 0 : width; | |
| 329 cone[1].y = (shape & SHAPE_CONE_TOP) ? 0 : height; | |
| 330 cone[2].x = (shape & SHAPE_CONE_LEFT) ? CONE_WIDTH : width - CONE_WIDTH; | |
| 331 cone[2].y = (shape & SHAPE_CONE_TOP) ? CONE_HEIGHT : height - CONE_HEIGHT; | |
| 332 | |
| 333 XFillPolygon (b_dpy, b_mask, b_maskGC, cone, 3, Nonconvex, CoordModeOrigin); | |
| 334 | |
| 335 } | |
| 336 | |
| 337 static void | |
| 2286 | 338 show_help (XtPointer UNUSED (data), XtIntervalId* id) |
| 428 | 339 { |
| 340 int x, y; | |
| 341 int shape; | |
| 342 XPoint border[ 3 ]; | |
| 343 | |
| 344 if (id == NULL || ((id && b_timer) && b_text)) | |
| 345 { | |
| 346 b_timer = None; | |
| 347 | |
| 348 /* size */ | |
| 349 get_text_size (b_dpy, b_fontStruct, b_text, &b_width, &b_height); | |
| 350 b_width += 2 * MARGIN_WIDTH + 2 * BORDER_WIDTH; | |
| 351 b_height += 2 * MARGIN_WIDTH + 2 * BORDER_WIDTH + CONE_HEIGHT; | |
| 352 | |
| 353 /* origin */ | |
| 354 get_pointer_xy (b_dpy, &x, &y); | |
| 355 | |
| 356 /* guess at shape */ | |
| 357 shape = get_shape(b_lastShape, x, y, b_width, b_height, | |
| 358 b_screenWidth, b_screenHeight); | |
| 359 | |
| 360 x += (shape & SHAPE_CONE_LEFT) ? POINTER_OFFSET : -POINTER_OFFSET; | |
| 361 y += (shape & SHAPE_CONE_TOP) ? POINTER_OFFSET : -POINTER_OFFSET; | |
| 362 | |
| 363 /* make sure it is still ok with offset */ | |
| 364 shape = get_shape (shape, x, y, b_width, b_height, b_screenWidth, b_screenHeight); | |
| 365 | |
| 366 b_lastShape = shape; | |
| 367 | |
| 368 make_mask (shape, x, y, b_width, b_height); | |
| 369 | |
| 370 XShapeCombineMask (b_dpy, b_win, ShapeBounding, 0, 0, b_mask, ShapeSet); | |
| 371 | |
| 372 XMoveResizeWindow(b_dpy, b_win, | |
| 373 (shape & SHAPE_CONE_LEFT) ? x : x - b_width, | |
| 374 (shape & SHAPE_CONE_TOP) ? y : y - b_height, | |
| 375 b_width, b_height); | |
| 376 | |
| 377 XClearWindow (b_dpy, b_win); | |
| 378 | |
| 379 XMapRaised (b_dpy, b_win); | |
| 380 b_winMapped = True; | |
| 381 | |
| 382 draw_text (b_dpy, b_win, b_gc, b_fontStruct, | |
| 383 BORDER_WIDTH + MARGIN_WIDTH, | |
| 384 BORDER_WIDTH + MARGIN_WIDTH + ((shape & SHAPE_CONE_TOP) ? CONE_HEIGHT : 0), | |
| 385 b_text); | |
| 386 | |
| 387 /* 3d border */ | |
| 388 /* shine- top left */ | |
| 389 border[0].x = 0 + BORDER_WIDTH_HALF; | |
| 390 border[0].y = ((shape & SHAPE_CONE_TOP) ? b_height : b_height - CONE_HEIGHT) - BORDER_WIDTH_HALF; | |
| 391 border[1].x = 0 + BORDER_WIDTH_HALF; | |
| 392 border[1].y = ((shape & SHAPE_CONE_TOP) ? CONE_HEIGHT : 0) + BORDER_WIDTH_HALF; | |
| 393 border[2].x = b_width - BORDER_WIDTH_HALF; | |
| 394 border[2].y = border[1].y; | |
| 395 XDrawLines (b_dpy, b_win, b_shineGC, border, 3, CoordModeOrigin); | |
| 396 | |
| 397 /* shadow- bottom right */ | |
| 398 border[0].x = 0 + BORDER_WIDTH_HALF; | |
| 399 border[0].y = ((shape & SHAPE_CONE_TOP) ? b_height : b_height - CONE_HEIGHT) - BORDER_WIDTH_HALF; | |
| 400 border[1].x = b_width - BORDER_WIDTH_HALF; | |
| 401 border[1].y = border[0].y; | |
| 402 border[2].x = b_width - BORDER_WIDTH_HALF; | |
| 403 border[2].y = ((shape & SHAPE_CONE_TOP) ? CONE_HEIGHT : 0) + BORDER_WIDTH_HALF; | |
| 404 XDrawLines (b_dpy, b_win, b_shadowGC, border, 3, CoordModeOrigin); | |
| 405 | |
| 406 /* cone */ | |
| 407 if (SHAPE_CONE_TOP_LEFT == shape) | |
| 408 { | |
| 409 XClearArea (b_dpy, b_win, | |
| 410 CONE_WIDTH / 2 + BORDER_WIDTH, | |
| 411 CONE_HEIGHT, | |
| 412 CONE_WIDTH / 2 - BORDER_WIDTH, | |
| 413 BORDER_WIDTH, False); | |
| 414 XDrawLine (b_dpy, b_win, b_shadowGC, | |
| 415 0, | |
| 416 0, | |
| 417 CONE_WIDTH / 2 + BORDER_WIDTH_HALF, | |
| 418 CONE_HEIGHT); | |
| 419 XDrawLine (b_dpy, b_win, b_shineGC, | |
| 420 0, | |
| 421 0, | |
| 422 CONE_WIDTH - BORDER_WIDTH_HALF, | |
| 423 CONE_HEIGHT); | |
| 424 } | |
| 425 else if (SHAPE_CONE_TOP_RIGHT == shape) | |
| 426 { | |
| 427 XClearArea (b_dpy, b_win, | |
| 428 b_width - CONE_WIDTH + BORDER_WIDTH, | |
| 429 CONE_HEIGHT, | |
| 430 CONE_WIDTH / 2 - BORDER_WIDTH, | |
| 431 BORDER_WIDTH, False); | |
| 432 XDrawLine (b_dpy, b_win, b_shadowGC, | |
| 433 b_width, | |
| 434 0, | |
| 435 b_width - CONE_WIDTH / 2 - BORDER_WIDTH_HALF, | |
| 436 CONE_HEIGHT); | |
| 437 XDrawLine (b_dpy, b_win, b_shineGC, | |
| 438 b_width, | |
| 439 0, | |
| 440 b_width - CONE_WIDTH + BORDER_WIDTH_HALF, | |
| 441 CONE_HEIGHT); | |
| 442 } | |
| 443 else if (SHAPE_CONE_BOTTOM_LEFT == shape) | |
| 444 { | |
| 445 XClearArea (b_dpy, b_win, | |
| 446 CONE_WIDTH / 2 + BORDER_WIDTH, | |
| 447 b_height - CONE_HEIGHT - BORDER_WIDTH, | |
| 448 CONE_WIDTH / 2 - BORDER_WIDTH, | |
| 449 BORDER_WIDTH, False); | |
| 450 XDrawLine (b_dpy, b_win, b_shadowGC, | |
| 451 0, | |
| 452 b_height - 1, | |
| 453 CONE_WIDTH, | |
| 454 b_height - 1 - CONE_HEIGHT); | |
| 455 XDrawLine (b_dpy, b_win, b_shineGC, | |
| 456 0, | |
| 457 b_height - 1, | |
| 458 CONE_WIDTH / 2 + BORDER_WIDTH, | |
| 459 b_height - 1 - CONE_HEIGHT); | |
| 460 } | |
| 461 else if (SHAPE_CONE_BOTTOM_RIGHT == shape) | |
| 462 { | |
| 463 XClearArea (b_dpy, b_win, | |
| 464 b_width - 1 - CONE_WIDTH + BORDER_WIDTH, | |
| 465 b_height - CONE_HEIGHT - BORDER_WIDTH, | |
| 466 CONE_WIDTH / 2 - BORDER_WIDTH - 1, | |
| 467 BORDER_WIDTH, False); | |
| 468 XDrawLine (b_dpy, b_win, b_shadowGC, | |
| 469 b_width - 1, | |
| 470 b_height - 1, | |
| 471 b_width - 1 - CONE_WIDTH, | |
| 472 b_height - 1 - CONE_HEIGHT); | |
| 473 XDrawLine (b_dpy, b_win, b_shineGC, | |
| 474 b_width - 1, | |
| 475 b_height - 1, | |
| 476 b_width - 1 - CONE_WIDTH / 2 - BORDER_WIDTH, | |
| 477 b_height - 1 - CONE_HEIGHT); | |
| 478 } | |
| 479 } | |
| 480 | |
| 481 } | |
| 482 | |
| 483 /*============================================================================ | |
| 484 | |
| 485 ============================================================================*/ | |
| 486 | |
| 487 static void | |
| 488 balloon_help_destroy (void) | |
| 489 { | |
| 490 assert (b_dpy != NULL); | |
| 491 b_dpy = NULL; | |
| 492 | |
| 493 destroy_window (b_dpy, b_win); | |
| 494 destroy_gc (b_dpy, b_gc); | |
| 495 | |
| 496 destroy_gc (b_dpy, b_shineGC); | |
| 497 destroy_gc (b_dpy, b_shadowGC); | |
| 498 | |
| 499 destroy_pixmap_mask (); | |
| 500 destroy_gc (b_dpy, b_maskGC); | |
| 501 | |
| 502 if (b_timer) XtRemoveTimeOut (b_timer); | |
| 503 } | |
| 504 | |
| 505 void | |
| 506 balloon_help_create (Display* dpy, | |
| 507 Pixel fg, Pixel bg, Pixel shine, Pixel shadow, | |
| 508 XFontStruct* font) | |
| 509 { | |
| 510 if (b_dpy) balloon_help_destroy (); | |
| 511 | |
| 512 b_dpy = dpy; | |
| 513 | |
| 514 b_fontStruct = font; | |
| 515 | |
| 516 b_win = create_window (dpy, bg); | |
| 517 b_gc = create_gc (dpy, b_win, fg, bg, b_fontStruct); | |
| 518 | |
| 519 b_shineGC = create_gc (dpy, b_win, shine, bg, b_fontStruct); | |
| 520 b_shadowGC = create_gc (dpy, b_win, shadow, bg, b_fontStruct); | |
| 521 | |
| 522 create_pixmap_mask (1, 1); | |
| 523 b_maskGC = create_gc (dpy, b_mask, bg, fg, b_fontStruct); | |
| 524 | |
| 525 b_winMapped = False; | |
| 526 b_timer = None; | |
| 527 b_delay = 500; | |
| 528 | |
| 529 b_screenWidth = DisplayWidth (b_dpy, DefaultScreen(b_dpy)); | |
| 530 b_screenHeight = DisplayHeight (b_dpy, DefaultScreen(b_dpy)); | |
| 531 | |
| 532 b_lastShape = SHAPE_CONE_FREE; | |
| 533 } | |
| 534 | |
| 535 void | |
| 536 balloon_help_set_delay (unsigned long milliseconds) | |
| 537 { | |
| 538 b_delay = milliseconds; | |
| 539 } | |
| 540 | |
| 541 void | |
| 442 | 542 balloon_help_show (const char* text) |
| 428 | 543 { |
| 544 assert (b_dpy != NULL); | |
| 545 | |
| 546 /* We don't copy the text */ | |
| 547 b_text = text; | |
| 548 b_lastShape = SHAPE_CONE_FREE; | |
| 549 | |
| 550 if (b_winMapped) | |
| 551 { | |
| 552 /* If help is already being shown, don't delay just update */ | |
| 553 show_help (NULL, NULL); | |
| 554 } | |
| 555 else | |
| 556 { | |
| 557 b_timer = | |
| 558 XtAppAddTimeOut (XtDisplayToApplicationContext(b_dpy), | |
| 559 b_delay, show_help, NULL); | |
| 560 } | |
| 561 } | |
| 562 | |
| 563 void | |
| 564 balloon_help_hide (void) | |
| 565 { | |
| 566 assert (b_dpy != NULL); | |
| 567 | |
| 568 b_text = NULL; | |
| 569 XUnmapWindow (b_dpy, b_win); | |
| 570 b_winMapped = False; | |
| 571 if (b_timer) | |
| 572 { | |
| 573 XtRemoveTimeOut (b_timer); | |
| 574 b_timer = None; | |
| 575 } | |
| 576 } | |
| 577 | |
| 578 void | |
| 579 balloon_help_move_to_pointer (void) | |
| 580 { | |
| 581 assert (b_dpy != NULL); | |
| 582 | |
| 583 if (b_winMapped) | |
| 584 { | |
| 585 int x, y; | |
| 586 int shape = b_lastShape; | |
| 587 | |
| 588 get_pointer_xy (b_dpy, &x, &y); | |
| 589 | |
| 590 x += (shape & SHAPE_CONE_LEFT) ? POINTER_OFFSET : -POINTER_OFFSET; | |
| 591 y += (shape & SHAPE_CONE_TOP) ? POINTER_OFFSET : -POINTER_OFFSET; | |
| 592 | |
| 593 shape = get_shape (shape, x, y, b_width, b_height, b_screenWidth, b_screenHeight); | |
| 594 | |
| 595 if (shape == b_lastShape) | |
| 596 { | |
| 597 XMoveWindow (b_dpy, b_win, | |
| 598 shape & SHAPE_CONE_LEFT ? x : x - b_width, | |
| 599 shape & SHAPE_CONE_TOP ? y : y - b_height); | |
| 600 } | |
| 601 else | |
| 602 { | |
| 603 /* text would be off screen, rebuild with new shape */ | |
| 604 b_lastShape = SHAPE_CONE_FREE; | |
| 605 show_help (NULL, NULL); | |
| 606 } | |
| 607 } | |
| 608 } |
