1 #include "unix/guts.h"
2 #include "Icon.h"
3
4 static int
5 cursor_map[] = {
6 /* crArrow => */ XC_left_ptr,
7 /* crText => */ XC_xterm,
8 /* crWait => */ XC_watch,
9 /* crSize => */ XC_sizing,
10 /* crMove => */ XC_fleur,
11 /* crSizeWest => */ XC_left_side,
12 /* crSizeEast => */ XC_right_side,
13 /* crSizeNE => */ XC_sb_h_double_arrow,
14 /* crSizeNorth => */ XC_top_side,
15 /* crSizeSouth => */ XC_bottom_side,
16 /* crSizeNS => */ XC_sb_v_double_arrow,
17 /* crSizeNW => */ XC_top_left_corner,
18 /* crSizeSE => */ XC_bottom_right_corner,
19 /* crSizeNE => */ XC_top_right_corner,
20 /* crSizeSW => */ XC_bottom_left_corner,
21 /* crInvalid => */ XC_X_cursor,
22 /* crDragNone => */ XC_X_cursor,
23 /* crDragCopy => */ XC_bottom_side,
24 /* crDragMove => */ XC_bottom_side,
25 /* crDragLink => */ XC_bottom_side,
26 /* crCrosshair => */ XC_crosshair,
27 /* crUpArrow => */ XC_sb_up_arrow,
28 /* crQuestionArrow => */ XC_question_arrow,
29 /* crHand => */ XC_hand2
30 };
31
32 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
33 static const char *
34 xcursor_map[] = {
35 /* crArrow => */ "left_ptr",
36 /* crText => */ "xterm",
37 /* crWait => */ "watch",
38 /* crSize => */ "sizing",
39 /* crMove => */ "fleur",
40 /* crSizeWest => */ "left_side",
41 /* crSizeEast => */ "right_side",
42 /* crSizeNE => */ "sb_h_double_arrow",
43 /* crSizeNorth => */ "top_side",
44 /* crSizeSouth => */ "bottom_side",
45 /* crSizeNS => */ "sb_v_double_arrow",
46 /* crSizeNW => */ "top_left_corner",
47 /* crSizeSE => */ "bottom_right_corner",
48 /* crSizeNE => */ "top_right_corner",
49 /* crSizeSW => */ "bottom_left_corner",
50 /* crInvalid => */ "X_cursor",
51 /* crDragNone => */ "dnd-none",
52 /* crDragCopy => */ "dnd-copy",
53 /* crDragMove => */ "dnd-move",
54 /* crDragLink => */ "dnd-link",
55 /* crCrosshair => */ "crosshair",
56 /* crUpArrow => */ "sb_up_arrow",
57 /* crQuestionArrow => */ "question_arrow",
58 /* crHand => */ "hand"
59 };
60 #endif
61
62 Cursor
63 predefined_cursors[] = {
64 /* crArrow => */ None,
65 /* crText => */ None,
66 /* crWait => */ None,
67 /* crSize => */ None,
68 /* crMove => */ None,
69 /* crSizeWest => */ None,
70 /* crSizeEast => */ None,
71 /* crSizeNE => */ None,
72 /* crSizeNorth => */ None,
73 /* crSizeSouth => */ None,
74 /* crSizeNS => */ None,
75 /* crSizeNW => */ None,
76 /* crSizeSE => */ None,
77 /* crSizeNE => */ None,
78 /* crSizeSW => */ None,
79 /* crInvalid => */ None,
80 /* crDragNone => */ None,
81 /* crDragCopy => */ None,
82 /* crDragMove => */ None,
83 /* crDragLink => */ None,
84 /* crCrosshair => */ None,
85 /* crUpArrow => */ None,
86 /* crQuestionArrow => */ None,
87 /* crHand => */ None,
88 /* crUser => */ None
89
90 };
91 static CustomPointer*
92 is_drag_cursor_available(int id);
93
94 static Bool
create_cursor(CustomPointer * cp,Handle icon,Point hot_spot)95 create_cursor(CustomPointer* cp, Handle icon, Point hot_spot)
96 {
97 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
98 XcursorImage* i;
99 PIcon c = PIcon(icon);
100 Bool kill;
101 int x, y;
102 XcursorPixel * dst;
103 Byte * src_data, * src_mask;
104
105 if ( hot_spot. x < 0) hot_spot. x = 0;
106 if ( hot_spot. y < 0) hot_spot. y = 0;
107 if ( hot_spot. x >= c-> w) hot_spot. x = c-> w - 1;
108 if ( hot_spot. y >= c-> h) hot_spot. y = c-> h - 1;
109 cp-> hot_spot = hot_spot;
110 if (( i = XcursorImageCreate( c-> w, c-> h )) == NULL) {
111 warn( "XcursorImageCreate(%d,%d) error", c->w, c->h);
112 return false;
113 }
114 i-> xhot = hot_spot. x;
115 i-> yhot = c-> h - hot_spot. y - 1;
116
117 if ( c-> type != imRGB || c-> maskType != imbpp8 ) {
118 icon = CIcon(icon)->dup(icon);
119 kill = true;
120 PIcon(icon)-> autoMasking = amNone;
121 CIcon(icon)-> set_type( icon, imRGB );
122 CIcon(icon)-> set_maskType( icon, imbpp8 );
123 } else
124 kill = false;
125 c = PIcon(icon);
126 src_data = c->data + c->lineSize * ( c-> h - 1 );
127 src_mask = c->mask + c->maskLine * ( c-> h - 1 );
128 dst = i->pixels;
129 for ( y = 0; y < c-> h; y++) {
130 Byte * s_data = src_data, * s_mask = src_mask;
131 for ( x = 0; x < c-> w; x++) {
132 *(dst++) =
133 s_data[0]|
134 (s_data[1] << 8)|
135 (s_data[2] << 16)|
136 (*(s_mask++) << 24)
137 ;
138 s_data += 3;
139 }
140 src_mask -= c->maskLine;
141 src_data -= c->lineSize;
142 }
143 if ( kill ) Object_destroy(icon);
144
145 cp-> cursor = XcursorImageLoadCursor(DISP, i);
146 if ( cp-> cursor == None) {
147 XcursorImageDestroy(i);
148 warn( "error creating cursor");
149 return false;
150 }
151 cp-> xcursor = i;
152
153 return true;
154
155 #else
156
157 Handle cursor;
158 Bool noSZ = PIcon(icon)-> w != guts.cursor_width || PIcon(icon)-> h != guts.cursor_height;
159 Bool noBPP = (PIcon(icon)-> type & imBPP) != 1;
160 XColor xcb, xcw;
161 PIcon c;
162
163 if ( noSZ || noBPP) {
164 cursor = CIcon(icon)->dup(icon);
165 c = PIcon(cursor);
166 if ( cursor == NULL_HANDLE) {
167 warn( "Error duping user cursor");
168 return false;
169 }
170 if ( noSZ) {
171 CIcon(cursor)-> stretch( cursor, guts.cursor_width, guts.cursor_height);
172 if ( c-> w != guts.cursor_width || c-> h != guts.cursor_height) {
173 warn( "Error stretching user cursor");
174 Object_destroy( cursor);
175 return false;
176 }
177 }
178 if ( noBPP) {
179 CIcon(cursor)-> set_type( cursor, imMono);
180 if ((c-> type & imBPP) != 1) {
181 warn( "Error black-n-whiting user cursor");
182 Object_destroy( cursor);
183 return false;
184 }
185 }
186 } else
187 cursor = icon;
188 if ( !prima_create_icon_pixmaps( cursor, &cp->xor, &cp->and)) {
189 warn( "Error creating user cursor pixmaps");
190 if ( noSZ || noBPP)
191 Object_destroy( cursor);
192 return false;
193 }
194 if ( noSZ || noBPP)
195 Object_destroy( cursor);
196 if ( hot_spot. x < 0) hot_spot. x = 0;
197 if ( hot_spot. y < 0) hot_spot. y = 0;
198 if ( hot_spot. x >= guts. cursor_width) hot_spot. x = guts. cursor_width - 1;
199 if ( hot_spot. y >= guts. cursor_height) hot_spot. y = guts. cursor_height - 1;
200 cp-> hot_spot = hot_spot;
201 xcb. red = xcb. green = xcb. blue = 0;
202 xcw. red = xcw. green = xcw. blue = 0xFFFF;
203 xcb. pixel = guts. monochromeMap[0];
204 xcw. pixel = guts. monochromeMap[1];
205 xcb. flags = xcw. flags = DoRed | DoGreen | DoBlue;
206 cp-> cursor = XCreatePixmapCursor( DISP, cp-> xor,
207 cp-> and, &xcw, &xcb,
208 hot_spot. x, guts.cursor_height - hot_spot. y - 1);
209 if ( cp-> cursor == None) {
210 warn( "error creating cursor from pixmaps");
211 return false;
212 }
213 return true;
214 #endif
215 }
216
217
218 static Bool
load_pointer_font(void)219 load_pointer_font( void)
220 {
221 if ( !guts.pointer_font)
222 guts.pointer_font = XLoadQueryFont( DISP, "cursor");
223 if ( !guts.pointer_font) {
224 warn( "Cannot load cursor font");
225 return false;
226 }
227 return true;
228 }
229
230 static void
draw_poly(Handle self,int n_points,Point * pts,int dx,int dy)231 draw_poly( Handle self, int n_points, Point * pts, int dx, int dy)
232 {
233 RegionRec rgnrec, *prgnrec;
234 PIcon i = (PIcon) self;
235 ImgPaintContext ctx = {
236 {0,0,0,0},
237 {0,0,0,0},
238 ropCopyPut, false,
239 {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
240 {0,0},
241 lpSolid,
242 NULL,
243 {dx,dy}
244 };
245 Image mask;
246 img_fill_dummy(&mask, i->w, i->h, i->maskType, i->mask, NULL);
247
248 Handle rgn = (Handle) create_object("Prima::Region", "");
249 apc_region_destroy(rgn);
250 rgnrec.type = rgnPolygon;
251 rgnrec.data.polygon.n_points = n_points;
252 rgnrec.data.polygon.points = pts;
253 rgnrec.data.polygon.fill_mode = fmWinding;
254 apc_region_create(rgn, &rgnrec);
255 apc_region_offset(rgn, dx, dy);
256 prgnrec = apc_region_copy_rects(rgn);
257 Object_destroy(rgn);
258
259 ctx.region = &prgnrec->data.box;
260 memset( &ctx.color, 0xff, sizeof(ctx.color));
261 img_bar( self, 0, 0, i->w, i-> h, &ctx);
262 memset( &ctx.color, 0x0, sizeof(ctx.color));
263 img_bar((Handle) &mask, 0, 0, i->w, i-> h, &ctx);
264 free(prgnrec);
265 ctx.region = NULL;
266
267 memset( &ctx.color, 0x0, sizeof(ctx.color));
268 img_polyline( self, n_points, pts, &ctx);
269 img_polyline((Handle) &mask, n_points, pts, &ctx);
270 }
271
272 static void
xdnd_synthesize_cursor(Handle self,int id)273 xdnd_synthesize_cursor(Handle self, int id)
274 {
275 PIcon i = (PIcon) self;
276 int side = ((i->h < i->w) ? i->h : i->w) / 2;
277 int s1 = side / 3; /* worst case 2 */
278 int s2 = s1 * 2;
279 int s3 = s1 * 3;
280
281 CIcon(self)->set_maskType(self, 1);
282
283 /* draw a little + = or arrow for copy,move,link in the bottom quarter */
284 switch ( id ) {
285 case crDragCopy: {
286 Point plus[13] = {
287 {s1, 0}, {s2, 0}, {s2, s1}, {s3, s1},
288 {s3, s2}, {s2, s2}, {s2, s3}, {s1, s3},
289 {s1, s2}, {0, s2}, {0, s1}, {s1, s1},
290 {s1, 0}
291 };
292 draw_poly( self, 13, plus, i->w/2, 0 );
293 break;
294 }
295 case crDragMove: {
296 Point arrow[10] = {
297 {s2, 0}, {s3, s1}, {s2, s2}, {s3, s2}, {s3, s3},
298 {0,s3}, {0,0}, {s1, 0}, {s1, s1}, {s2, 0},
299 };
300 draw_poly( self, 10, arrow, i->w/2, 0 );
301 break;
302 }
303 case crDragLink: {
304 Point bar[5] = {{0, 0}, {s1, 0}, {s1, s1}, {0, s1}, {0, 0}};
305 draw_poly( self, 5, bar, i->w/2, 0 );
306 draw_poly( self, 5, bar, i->w/2 + s1, s1);
307 draw_poly( self, 5, bar, i->w/2 + s2, s2);
308 break;
309 }}
310 }
311
312 static Point
get_predefined_hot_spot(int id)313 get_predefined_hot_spot( int id)
314 {
315 int idx;
316 XFontStruct *fs;
317 XCharStruct *cs;
318 Point ret = {0,0};
319
320 if ( id < crDefault || id >= crUser) return ret;
321
322 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
323 {
324 XcursorImage * i;
325 if (( i = XcursorLibraryLoadImage( xcursor_map[id] , NULL, guts. cursor_width )) != NULL) {
326 ret.x = i->xhot;
327 ret.y = i->height - i->yhot - 1;
328 XcursorImageDestroy(i);
329 return ret;
330 }
331 }
332 #endif
333
334 if ( !load_pointer_font()) return ret;
335
336 idx = cursor_map[id];
337 fs = guts.pointer_font;
338 if ( !fs-> per_char)
339 cs = &fs-> min_bounds;
340 else if ( idx < fs-> min_char_or_byte2 || idx > fs-> max_char_or_byte2) {
341 int default_char = fs-> default_char;
342 if ( default_char < fs-> min_char_or_byte2 || default_char > fs-> max_char_or_byte2)
343 default_char = fs-> min_char_or_byte2;
344 cs = fs-> per_char + default_char - fs-> min_char_or_byte2;
345 } else
346 cs = fs-> per_char + idx - fs-> min_char_or_byte2;
347 ret. x = -cs->lbearing;
348 ret. y = guts.cursor_height - cs->ascent;
349 if ( ret. x < 0) ret. x = 0;
350 if ( ret. y < 0) ret. y = 0;
351 if ( ret. x >= guts. cursor_width) ret. x = guts. cursor_width - 1;
352 if ( ret. y >= guts. cursor_height) ret. y = guts. cursor_height - 1;
353 return ret;
354 }
355
356 static Bool
xlib_cursor_load(Handle self,int id,Handle icon)357 xlib_cursor_load( Handle self, int id, Handle icon)
358 {
359 XImage *im;
360 Pixmap p1 = None, p2 = None;
361 Bool free_pixmap = true, success = false;
362 GC gc;
363 XGCValues gcv;
364 char c;
365 int w = guts.cursor_width, h = guts.cursor_height;
366 CustomPointer *cp = NULL;
367
368 cp = is_drag_cursor_available(id);
369 if ( cp != NULL ) {
370 free_pixmap = false;
371 } else if ( id == crUser ) {
372 if ( !self ) return false;
373 cp = &X(self)->user_pointer;
374 free_pixmap = false;
375 } else {
376 XFontStruct *fs;
377 XCharStruct *cs;
378 int idx = cursor_map[id];
379
380 if ( !load_pointer_font()) return false;
381 fs = guts.pointer_font;
382 if ( !fs-> per_char)
383 cs = &fs-> min_bounds;
384 else if ( idx < fs-> min_char_or_byte2 || idx > fs-> max_char_or_byte2) {
385 int default_char = fs-> default_char;
386 if ( default_char < fs-> min_char_or_byte2 || default_char > fs-> max_char_or_byte2)
387 default_char = fs-> min_char_or_byte2;
388 cs = fs-> per_char + default_char - fs-> min_char_or_byte2;
389 } else
390 cs = fs-> per_char + idx - fs-> min_char_or_byte2;
391
392 p1 = XCreatePixmap( DISP, guts. root, w, h, 1);
393 p2 = XCreatePixmap( DISP, guts. root, w, h, 1);
394 gcv. background = 1;
395 gcv. foreground = 0;
396 gcv. font = guts.pointer_font-> fid;
397 gc = XCreateGC( DISP, p1, GCBackground | GCForeground | GCFont, &gcv);
398 XFillRectangle( DISP, p1, gc, 0, 0, w, h);
399 gcv. background = 0;
400 gcv. foreground = 1;
401 XChangeGC( DISP, gc, GCBackground | GCForeground, &gcv);
402 XFillRectangle( DISP, p2, gc, 0, 0, w, h);
403 XDrawString( DISP, p1, gc, 1-cs-> lbearing, 1+cs-> ascent, (c = (char)(idx+1), &c), 1);
404 gcv. background = 1;
405 gcv. foreground = 0;
406 XChangeGC( DISP, gc, GCBackground | GCForeground, &gcv);
407 XDrawString( DISP, p2, gc, 1-cs-> lbearing, 1+cs-> ascent, (c = (char)(idx+1), &c), 1);
408 XDrawString( DISP, p1, gc, 1-cs-> lbearing, 1+cs-> ascent, (c = (char)idx, &c), 1);
409 XFreeGC( DISP, gc);
410 }
411 if ( cp != NULL ) {
412 p1 = cp-> xor;
413 p2 = cp-> and;
414 }
415 CIcon(icon)-> create_empty( icon, w, h, imBW);
416 if (( im = XGetImage( DISP, p1, 0, 0, w, h, 1, XYPixmap)) == NULL)
417 goto FAIL;
418 prima_copy_xybitmap(
419 PIcon(icon)-> data, (Byte*)im-> data,
420 PIcon(icon)-> w, PIcon(icon)-> h,
421 PIcon(icon)-> lineSize, im-> bytes_per_line);
422 XDestroyImage( im);
423 if (( im = XGetImage( DISP, p2, 0, 0, w, h, 1, XYPixmap)) == NULL)
424 goto FAIL;
425 prima_copy_xybitmap(
426 PIcon(icon)-> mask, (Byte*)im-> data,
427 PIcon(icon)-> w, PIcon(icon)-> h,
428 PIcon(icon)-> maskLine, im-> bytes_per_line);
429 if ( cp != NULL ) {
430 int i;
431 Byte * mask = PIcon(icon)-> mask;
432 for ( i = 0; i < PIcon(icon)-> maskSize; i++)
433 mask[i] = ~mask[i];
434 }
435 success = true;
436 FAIL:
437 if (im != NULL) XDestroyImage( im);
438 if ( free_pixmap) {
439 XFreePixmap( DISP, p1);
440 XFreePixmap( DISP, p2);
441 }
442 return success;
443 }
444
445
446 static Bool
create_xdnd_pointer(int id,CustomPointer * cp)447 create_xdnd_pointer(int id, CustomPointer* cp)
448 {
449 Handle self;
450 if ( cp-> status > 0 ) return true;
451 if ( cp-> status < 0 ) return false;
452
453 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
454 if (( cp->xcursor = XcursorLibraryLoadImage( xcursor_map[id] , NULL, guts. cursor_width )) != NULL) {
455 if ((cp-> cursor = XcursorImageLoadCursor(DISP, cp->xcursor)) != None) {
456 cp-> hot_spot.x = cp->xcursor->xhot;
457 cp-> hot_spot.y = cp->xcursor->height - cp->xcursor->yhot - 1;
458 cp-> status = 1;
459 return true;
460 } else {
461 XcursorImageDestroy(cp-> xcursor);
462 cp-> xcursor = NULL;
463 }
464 }
465 #endif
466
467 if ( id == crDragNone ) {
468 /* X11 has good enough glyphs for this */
469 cp->status = -1;
470 return true;
471 }
472
473 self = (Handle) create_object("Prima::Icon", "");
474 xlib_cursor_load(NULL_HANDLE, crArrow, self);
475 if ( PImage(self)->w < 16 || PImage(self)->h < 16 ) {
476 /* too small */
477 cp-> status = -1;
478 Object_destroy(self);
479 return false;
480 }
481 xdnd_synthesize_cursor(self, id);
482
483 cp-> status = 1;
484 create_cursor(cp, self, get_predefined_hot_spot(crArrow));
485 Object_destroy(self);
486
487 return true;
488 }
489
490 static CustomPointer*
is_drag_cursor_available(int id)491 is_drag_cursor_available(int id)
492 {
493 if ( id >= crDragNone && id <= crDragLink ) {
494 CustomPointer *cp = guts.xdnd_pointers + id - crDragNone;
495 if (cp->status == 0)
496 create_xdnd_pointer(id, cp);
497 return (cp->status > 0) ? cp : NULL;
498 }
499 return NULL;
500 }
501
502 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
503 static Bool
xcursor_load(Handle self,int id,Handle icon)504 xcursor_load( Handle self, int id, Handle icon)
505 {
506 PIcon c;
507 int x, y;
508 XcursorPixel * src;
509 XcursorImage* i = NULL;
510 Byte * dst_data, * dst_mask;
511 Bool kill = false;
512 CustomPointer* cp;
513
514 if (( cp = is_drag_cursor_available(id)) != NULL ) {
515 i = cp->xcursor;
516 goto READ_BITMAP;
517 }
518
519 if ( i == NULL && id != crUser ) {
520 if (( i = XcursorLibraryLoadImage( xcursor_map[id] , NULL, guts. cursor_width )) == NULL)
521 return false;
522 kill = true;
523 } else if ( self ) {
524 DEFXX;
525 i = XX-> user_pointer.xcursor;
526 kill = false;
527 } else
528 return false;
529
530 READ_BITMAP:
531 c = PIcon(icon);
532 CIcon(icon)-> create_empty_icon( icon, i->width, i->height, imRGB, imbpp8);
533 dst_data = c->data + c->lineSize * ( c-> h - 1 );
534 dst_mask = c->mask + c->maskLine * ( c-> h - 1 );
535 src = i->pixels;
536 for ( y = 0; y < c-> h; y++) {
537 Byte * d_data = dst_data, * d_mask = dst_mask;
538 for ( x = 0; x < c-> w; x++) {
539 *d_data++ = *src & 0xff;
540 *d_data++ = (*src >> 8) & 0xff;
541 *d_data++ = (*src >> 16) & 0xff;
542 *d_mask++ = (*src >> 24) & 0xff;
543 src++;
544 }
545 dst_mask -= c->maskLine;
546 dst_data -= c->lineSize;
547 }
548 if ( kill ) XcursorImageDestroy(i);
549 return true;
550 }
551 #endif
552
553 static int
get_cursor(Handle self,Pixmap * source,Pixmap * mask,Point * hot_spot,Cursor * cursor)554 get_cursor( Handle self, Pixmap *source, Pixmap *mask, Point *hot_spot, Cursor *cursor)
555 {
556 CustomPointer *cp = NULL;
557 int id = X(self)-> pointer_id;
558
559 while ( self && ( id = X(self)-> pointer_id) == crDefault)
560 self = PWidget(self)-> owner;
561 switch ( id ) {
562 case crDefault:
563 id = crArrow;
564 break;
565 case crUser:
566 cp = &X(self)->user_pointer;
567 break;
568 default:
569 cp = is_drag_cursor_available(id);
570 break;
571 }
572
573 if ( cp ) {
574 if (source) *source = cp->xor;
575 if (mask) *mask = cp->and;
576 if (hot_spot) *hot_spot = cp->hot_spot;
577 if (cursor) *cursor = cp->cursor;
578 }
579
580 return id;
581 }
582
583 Cursor
prima_get_cursor(Handle self)584 prima_get_cursor(Handle self)
585 {
586 DEFXX;
587 CustomPointer* cp;
588 if ( XX-> flags. pointer_obscured )
589 return prima_null_pointer();
590 else if ( XX->pointer_id == crUser )
591 return XX-> user_pointer.cursor;
592 else if (( cp = is_drag_cursor_available( XX-> pointer_id )) != NULL )
593 return cp->cursor;
594 else
595 return XX->actual_pointer;
596 }
597
598 Point
apc_pointer_get_hot_spot(Handle self)599 apc_pointer_get_hot_spot( Handle self)
600 {
601 Point hot_spot;
602 int id = get_cursor(self, NULL, NULL, &hot_spot, NULL);
603 return (id == crUser || is_drag_cursor_available(id) != NULL)
604 ? hot_spot : get_predefined_hot_spot(id);
605 }
606
607 Point
apc_pointer_get_pos(Handle self)608 apc_pointer_get_pos( Handle self)
609 {
610 Point p;
611 XWindow root, child;
612 int x, y;
613 unsigned int mask;
614
615 if ( !XQueryPointer( DISP, guts. root,
616 &root, &child, &p. x, &p. y,
617 &x, &y, &mask))
618 return guts. displaySize;
619 p. y = guts. displaySize. y - p. y - 1;
620 return p;
621 }
622
623 int
apc_pointer_get_shape(Handle self)624 apc_pointer_get_shape( Handle self)
625 {
626 return X(self)->pointer_id;
627 }
628
629 Point
apc_pointer_get_size(Handle self)630 apc_pointer_get_size( Handle self)
631 {
632 Point p;
633 p.x = guts.cursor_width;
634 p.y = guts.cursor_height;
635 return p;
636 }
637
638 Bool
apc_pointer_get_bitmap(Handle self,Handle icon)639 apc_pointer_get_bitmap( Handle self, Handle icon)
640 {
641 int id = get_cursor( self, NULL, NULL, NULL, NULL);
642 if ( id < crDefault || id > crUser) return false;
643
644 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
645 if (xcursor_load(self, id, icon))
646 return true;
647 #endif
648 return xlib_cursor_load(self, id, icon);
649 }
650
651 Bool
apc_pointer_get_visible(Handle self)652 apc_pointer_get_visible( Handle self)
653 {
654 return guts. pointer_invisible_count == 0;
655 }
656
657 Bool
apc_pointer_set_pos(Handle self,int x,int y)658 apc_pointer_set_pos( Handle self, int x, int y)
659 {
660 XEvent ev;
661 if ( !XWarpPointer( DISP, None, guts. root,
662 0, 0, guts. displaySize.x, guts. displaySize.y, x, guts. displaySize.y - y - 1))
663 return false;
664 XCHECKPOINT;
665 XSync( DISP, false);
666 while ( XCheckMaskEvent( DISP, PointerMotionMask|EnterWindowMask|LeaveWindowMask, &ev))
667 prima_handle_event( &ev, NULL);
668 return true;
669 }
670
671 Bool
apc_pointer_set_shape(Handle self,int id)672 apc_pointer_set_shape( Handle self, int id)
673 {
674 DEFXX;
675 Cursor uc = None;
676
677 if ( id < crDefault || id > crUser) return false;
678 XX-> pointer_id = id;
679 id = get_cursor( self, NULL, NULL, NULL, &uc);
680 if ( id == crUser || is_drag_cursor_available(id)) {
681 if ( uc != None ) {
682 if ( self != application) {
683 if ( guts. pointer_invisible_count < 0) {
684 if ( !XX-> flags. pointer_obscured) {
685 XDefineCursor( DISP, XX-> udrawable, prima_null_pointer());
686 XX-> flags. pointer_obscured = 1;
687 }
688 } else {
689 XDefineCursor( DISP, XX-> udrawable, uc);
690 XX-> flags. pointer_obscured = 0;
691 }
692 XCHECKPOINT;
693 }
694 } else
695 id = crArrow;
696 } else {
697 if ( predefined_cursors[id] == None) {
698 predefined_cursors[id] =
699 XCreateFontCursor( DISP, cursor_map[id]);
700 XCHECKPOINT;
701 }
702 XX-> actual_pointer = predefined_cursors[id];
703 if ( self != application) {
704 if ( guts. pointer_invisible_count < 0) {
705 if ( !XX-> flags. pointer_obscured) {
706 XDefineCursor( DISP, XX-> udrawable, prima_null_pointer());
707 XX-> flags. pointer_obscured = 1;
708 }
709 } else {
710 XDefineCursor( DISP, XX-> udrawable, predefined_cursors[id]);
711 XX-> flags. pointer_obscured = 0;
712 }
713 XCHECKPOINT;
714 }
715 }
716 XFlush( DISP);
717 if ( guts. grab_widget)
718 apc_widget_set_capture( guts. grab_widget, true, guts. grab_confine);
719 return true;
720 }
721
722 Bool
apc_pointer_set_user(Handle self,Handle icon,Point hot_spot)723 apc_pointer_set_user( Handle self, Handle icon, Point hot_spot)
724 {
725 DEFXX;
726
727 if ( XX-> user_pointer.cursor != None) {
728 XFreeCursor( DISP, XX-> user_pointer.cursor);
729 XX-> user_pointer.cursor = None;
730 }
731 if ( XX-> user_pointer.xor != None) {
732 XFreePixmap( DISP, XX-> user_pointer.xor);
733 XX-> user_pointer.xor = None;
734 }
735 if ( XX-> user_pointer.and != None) {
736 XFreePixmap( DISP, XX-> user_pointer.and);
737 XX-> user_pointer.and = None;
738 }
739 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
740 if ( XX-> user_pointer.xcursor != NULL) {
741 XcursorImageDestroy(XX-> user_pointer.xcursor);
742 XX-> user_pointer.xcursor = NULL;
743 }
744 #endif
745 if ( icon != NULL_HANDLE) {
746 Bool ok;
747 ok = create_cursor(&XX->user_pointer, icon, hot_spot);
748 if ( !ok ) return false;
749
750 if ( XX-> pointer_id == crUser && self != application) {
751 if ( guts. pointer_invisible_count < 0) {
752 if ( !XX-> flags. pointer_obscured) {
753 XDefineCursor( DISP, XX-> udrawable, prima_null_pointer());
754 XX-> flags. pointer_obscured = 1;
755 }
756 } else {
757 XDefineCursor( DISP, XX-> udrawable, XX-> user_pointer.cursor);
758 XX-> flags. pointer_obscured = 0;
759 }
760 XCHECKPOINT;
761 }
762 }
763 XFlush( DISP);
764 if ( guts. grab_widget)
765 apc_widget_set_capture( guts. grab_widget, true, guts. grab_confine);
766 return true;
767 }
768
769 Bool
apc_pointer_set_visible(Handle self,Bool visible)770 apc_pointer_set_visible( Handle self, Bool visible)
771 {
772 /* maintaining hide/show count */
773 if ( visible) {
774 if ( guts. pointer_invisible_count == 0)
775 return true;
776 if ( ++guts. pointer_invisible_count < 0)
777 return true;
778 } else {
779 if ( guts. pointer_invisible_count-- < 0)
780 return true;
781 }
782
783 /* setting pointer for widget under cursor */
784 {
785 Point p = apc_pointer_get_pos( application);
786 Handle wij = apc_application_get_widget_from_point( application, p);
787 if ( wij) {
788 X(wij)-> flags. pointer_obscured = (visible ? 0 : 1);
789 XDefineCursor( DISP, X(wij)-> udrawable, prima_get_cursor(wij));
790 }
791 }
792 XFlush( DISP);
793 if ( guts. grab_widget)
794 apc_widget_set_capture( guts. grab_widget, true, guts. grab_confine);
795 return true;
796 }
797
798 Cursor
prima_null_pointer(void)799 prima_null_pointer( void)
800 {
801 if ( guts. null_pointer == NULL_HANDLE) {
802 Handle nullc = ( Handle) create_object( "Prima::Icon", "", NULL);
803 PIcon n = ( PIcon) nullc;
804 Pixmap xor, and;
805 XColor xc;
806 if ( nullc == NULL_HANDLE) {
807 warn("Error creating icon object");
808 return NULL_HANDLE;
809 }
810 n-> self-> create_empty( nullc, 16, 16, imBW);
811 memset( n-> mask, 0xFF, n-> maskSize);
812 if ( !prima_create_icon_pixmaps( nullc, &xor, &and)) {
813 warn( "Error creating null cursor pixmaps");
814 Object_destroy( nullc);
815 return NULL_HANDLE;
816 }
817 Object_destroy( nullc);
818 xc. red = xc. green = xc. blue = 0;
819 xc. pixel = guts. monochromeMap[0];
820 xc. flags = DoRed | DoGreen | DoBlue;
821 guts. null_pointer = XCreatePixmapCursor( DISP, xor, and, &xc, &xc, 0, 0);
822 XCHECKPOINT;
823 XFreePixmap( DISP, xor);
824 XFreePixmap( DISP, and);
825 if ( !guts. null_pointer) {
826 warn( "Error creating null cursor from pixmaps");
827 return NULL_HANDLE;
828 }
829 }
830 return guts. null_pointer;
831 }
832