1 /*--- xwindow.c ----------------------------------------------------------------
2 Copyright (C) 2004, 2005 Sylvain Fourmanoit <syfou@users.sourceforge.net>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to
6 deal in the Software without restriction, including without limitation the
7 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 sell copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies of the Software and its documentation and acknowledgment shall be
13 given in the documentation and software packages that this Software was
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 ------------------------------------------------------------------------------*/
23 /* Miscellaneous routines related to X Windows */
25 /*----------------------------------------------------------------------------*/
26 #include "xwindow.h" /* X Windows related stuff */
29 #include <libgen.h> /* dirname() function */
33 #include <string.h> /* strlen, strcpy functions */
36 /*----------------------------------------------------------------------------*/
37 #ifndef X_DISPLAY_MISSING
38 XSetWindowAttributes XDefaultWindowAttributes
= {
39 ParentRelative
, /* Pixmap background_pixmap */
40 0L, /* unsigned long background_pixel */
41 0, /* Pixmap border_pixmap */
42 0L, /* unsigned long border_pixel */
43 0, /* int bit_gravity */
44 0, /* int win_gravity */
45 Always
, /* int backing_store */
46 0L, /* unsigned long backing_planes */
47 0L, /* unsigned long backing_pixel */
48 False
, /* Bool save_under */
49 BASE_EVENT_MASK
, /* long event_mask */
50 0L, /* long do_not_propagate_mask */
51 True
, /* Bool override_redirect */
52 0, /* Colormap colormap */
56 XErrorEvent xerror_event
= {
58 NULL
, /* Display *display */
59 0L, /* unsigned long serial */
60 0, /* unsigned char error_code */
61 0, /* unsigned char request_code */
62 0, /* unsigned char minor_code */
63 0 /* XID resourceid */
67 /*----------------------------------------------------------------------------*/
68 typedef struct s_context_backup
{
79 Imlib_Color_Modifier color_modifier
;
80 Imlib_Color_Range color_range
;
81 Imlib_Operation operation
;
83 Imlib_Text_Direction direction
;
93 vector
* contextes
= NULL
;
95 /*----------------------------------------------------------------------------*/
96 /* If present on the system, uses fontconfig to find all paths
97 containing truetype fonts: reused almost verbatim from fc-list source.
100 xwindow_locate_truetype_fonts(void)
102 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
110 if (strlen(PKGDATADIR
))
111 imlib_add_path_to_font_path(PKGDATADIR
);
113 #ifdef HAVE_FONTCONFIG_FONTCONFIG_H
115 pat
= FcNameParse((FcChar8
*)":");
116 os
= FcObjectSetCreate();
117 FcObjectSetAdd(os
, "file");
118 fs
= FcFontList(0, pat
, os
);
119 if(pat
) FcPatternDestroy(pat
);
121 for (j
= 0; j
< fs
->nfont
; j
++)
122 if (FcPatternGetString(fs
->fonts
[j
], FC_FILE
, 0, &file
)==FcResultMatch
)
123 if ((strlen((char*)file
)>4) &&
124 (strstr((char*)file
+strlen((char*)file
)-4,".ttf")))
125 imlib_add_path_to_font_path(dirname((char*)file
));
126 FcFontSetDestroy(fs
);
127 FcObjectSetDestroy(os
);
131 imlib_add_path_to_font_path(".");
133 imlib_add_path_to_font_path("../sharedata");
137 /*----------------------------------------------------------------------------*/
138 #ifndef X_DISPLAY_MISSING
141 xwindow_non_fatal_error_handler(Display
* display
, XErrorEvent
* ev
)
145 if(!display
) return 0;
147 /* Print out error description */
148 if (!XGetErrorText(display
,ev
->error_code
,buffer
,sizeof(buffer
)))
149 fprintf(stderr
,"Error: with X protocol on display `%s'\n%s\n",
150 XDisplayName(NULL
),buffer
);
151 /* Save error description */
152 memcpy(&xerror_event
,ev
,sizeof(XErrorEvent
));
156 /*----------------------------------------------------------------------------*/
158 xwindow_error_reset(void)
160 memset(&xerror_event
,0,sizeof(XErrorEvent
));
163 /*----------------------------------------------------------------------------*/
165 xwindow_error_check(void)
167 return xerror_event
.error_code
==0;
170 /*----------------------------------------------------------------------------*/
171 /* Sends back dimensions of given window. */
173 xwindow_window_size(Display
* display
, Window window
,
174 uint
* width_return
, uint
* height_return
)
178 return display
&& window
&&
179 XGetGeometry(display
, window
, &root
,
180 &dummy
, &dummy
, width_return
, height_return
,
181 (uint
*)&dummy
,(uint
*)&dummy
);
184 /*----------------------------------------------------------------------------*/
185 /* Return 1 if given coordinates changed since last call.
186 Note: only works with one set of coordinates */
188 xwindow_window_moved_or_resized(int new_x
, int new_y
,
189 int new_width
, int new_height
)
191 static int x
=-1, y
=-1, width
=-1, height
=-1;
193 result
=!(x
==new_x
&& y
==new_y
&& width
==new_width
&& height
==new_height
);
194 x
=new_x
;y
=new_y
;width
=new_width
;height
=new_height
;
198 /*----------------------------------------------------------------------------*/
199 /* Returns 1 if background has changed since last call, 0 otherwise.
200 This is enlightment mechanism. Go read:
201 http://gershwin.ens.fr/vdaniel/Doc-Locale/Outils-Gnu-Linux/Eterm-0.9/#trans
202 NOTE: this will always returns 0 when this mechanism is not supported.
205 xwindow_updated_background(Display
* display
, Window root
, Atom id
)
208 static Pixmap old_pixmap
= None
;
209 Pixmap pixmap
= None
;
212 unsigned long nitems
, bytes_after
;
213 unsigned char *prop
= NULL
;
215 if (!(display
&& root
)) return 0;
217 if(id
==None
) id
=XInternAtom(display
,"_XROOTPMAP_ID", True
);
219 XGetWindowProperty(display
, root
, id
, 0, 1, False
, XA_PIXMAP
,
220 &act_type
, &act_format
, &nitems
, &bytes_after
,
223 pixmap
= *((Pixmap
*)prop
);
224 result
=(old_pixmap
!=pixmap
);
232 /*----------------------------------------------------------------------------*/
233 /* Routine to grab the background in Imlib_Image.
234 Returns NULL if it fails, Reference to output Imlib_Image otherwise.
237 xwindow_grab_background(Display
* display
, int screen
, Window window
)
242 XWindowAttributes attr
;
243 Imlib_Image background
=NULL
;
245 if (!(display
&& window
)) return NULL
;
247 if(XGetWindowAttributes(display
,window
,&attr
) &&
248 /* Avoid reparenting coordinates translation problem */
249 XTranslateCoordinates(display
,window
,RootWindow(display
,screen
),
250 0, 0, &x
, &y
, &src
)) {
251 /* The trick is to create an Overrideredirect window overlapping our
252 window with background type of Parent relative and then grab it.
253 It seems overkill, but:
254 - XGetImage() on root get all viewable children windows embedded.
255 - XCopyArea() cause potential synchronisation problems depending
256 on backing store settings of root window: playing around
257 with GraphicsExpose events is not quicker nor simpler.
259 This idea was taken from aterm source base. See src/pixmap.c
260 in core distribution (http://aterm.sourceforge.net/).
262 if((src
=XCreateWindow(display
,
263 RootWindow(display
,screen
),
264 x
, y
, attr
.width
, attr
.height
,
266 CopyFromParent
, CopyFromParent
, CopyFromParent
,
267 CWBackPixmap
|CWBackingStore
|
268 CWOverrideRedirect
|CWEventMask
,
269 &XDefaultWindowAttributes
))) {
270 xwindow_context_save(IMLIB_DRAWABLE
|IMLIB_IMAGE
);
271 XGrabServer(display
);
272 XMapRaised(display
,src
);
273 XSync(display
,False
);
275 XWindowEvent(display
, src
, ExposureMask
, &ev
);
276 while(ev
.type
!=Expose
);
277 imlib_context_set_drawable(src
);
278 background
=imlib_create_image_from_drawable(0,0,0,
279 attr
.width
,attr
.height
,0);
280 XUngrabServer(display
);
281 XDestroyWindow(display
,src
);
283 /* Make sure image has an alpha channel */
284 imlib_context_set_image(background
);
285 imlib_image_set_has_alpha(1);
287 /* Restore context */
288 xwindow_context_restore();
294 /*----------------------------------------------------------------------------*/
295 /* Redraw updates rectangles onto window by copying background image at same
299 xwindow_update_window(Window window
, Imlib_Updates
* updates
,
300 Imlib_Image background
, Imlib_Image foreground
,
301 int transparency_flag
)
303 int x
,y
,width
,height
;
305 Imlib_Updates update
;
307 /* Verify there is something to update */
308 if(window
&& *updates
) {
309 /* Save context states */
310 xwindow_context_save(IMLIB_IMAGE
|IMLIB_COLOR
|IMLIB_OPERATION
|
311 IMLIB_BLEND
|IMLIB_COLOR_MODIFIER
|IMLIB_FILTER
|
314 /* Pre-loop settings */
315 imlib_context_set_drawable(window
);
316 imlib_context_set_blend(0);
317 imlib_context_set_color_modifier(NULL
);
318 imlib_context_set_filter(NULL
);
319 if(transparency_flag
) {
320 imlib_context_set_operation(IMLIB_OP_COPY
);
322 imlib_context_set_image(foreground
);
324 /* Loop over updates */
327 update
=imlib_updates_get_next(update
)) {
328 imlib_updates_get_coordinates(update
,&x
,&y
,(int*)&width
,(int*)&height
);
329 if (transparency_flag
) {
330 if((image
=imlib_create_image(width
,height
))) {
331 imlib_context_set_image(image
);
333 /* Make sur the alpha channel is detected */
334 imlib_image_set_has_alpha(1);
336 /* Fill image wih full opaque black, then copy
338 imlib_context_set_color(0,0,0,255);
339 imlib_image_fill_rectangle(0,0,width
,height
);
340 imlib_blend_image_onto_image(background
,0,
344 /* Blend foreground over background */
345 imlib_context_set_blend(1);
346 imlib_blend_image_onto_image(foreground
,1,
350 /* Copy image to drawable and free it */
351 imlib_context_set_blend(0);
352 imlib_render_image_on_drawable(x
,y
);
356 /* Otherwise, just copy foreground, without alteration */
357 imlib_render_image_part_on_drawable_at_size(x
,y
,width
,height
,
361 /* Restore initial context states */
362 xwindow_context_restore();
366 /*----------------------------------------------------------------------------*/
367 /* This move a window using outline rectangles if a window is mapped, and
368 updates cfgfile_item params accordingly. This is used by adesklets
369 if we created an `override_notify' window, and that therefore cannot take
370 advantage of any windows manager. Returns 1 if the window has been moved,
372 NOTE: The window is not remmaped at the end if the move was sucessfull:
373 it is the duty of the caller to do so.
376 xwindow_move_window(Display
* display
, Window root
, Window window
,
377 cfgfile_item
* params
)
379 int dummy
, grab_x
, grab_y
, old_x
, old_y
, x
=0, y
=0, result
=0;
380 uint screen_width
, screen_height
;
381 XWindowAttributes attr
;
388 if (!(display
&& window
)) return 0;
390 /* Test that main window is mapped,
391 and if screen size could be known */
392 if(XGetWindowAttributes(display
,window
,&attr
) &&
393 attr
.map_state
!=IsUnmapped
&&
394 xwindow_window_size(display
,root
,&screen_width
,&screen_height
)) {
395 /* Initialize a graphics context for the root window behind ours */
396 xgcvalues
.function
=GXxor
;
397 xgcvalues
.foreground
=WhitePixel(display
,params
->scr
);
398 xwindow_error_reset();
399 gc
=XCreateGC(display
,root
,GCFunction
|GCForeground
,&xgcvalues
);
400 /* Initialize cursor */
401 cursor
= XCreateFontCursor(display
,XC_fleur
);
402 /* Initialize old coordinates */
403 old_x
=attr
.x
; old_y
=attr
.y
;
404 /* Unmap the window */
405 if (xwindow_error_check() &&
406 XUnmapWindow(display
,window
)) {
407 /* Query, then grab the pointer */
408 if(XQueryPointer(display
, window
, &dummy_window
,
409 &dummy_window
, &grab_x
, &grab_y
,
410 &dummy
, &dummy
, (uint
*)&dummy
) &&
411 XGrabPointer(display
,root
,True
,
412 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
413 GrabModeAsync
,GrabModeAsync
,
414 root
, cursor
, 0)==GrabSuccess
) {
415 /* Draw initial rectangle */
416 XDrawRectangle(display
,root
,gc
,
417 attr
.x
,attr
.y
,attr
.width
-1,attr
.height
-1);
420 XWindowEvent(display
,root
,
421 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
428 /* We want a button press in our window before we take
429 this into account: the idea is that we want to ignore
430 button release event from menu */
432 /* Erase final rectangle */
433 XDrawRectangle(display
,root
,gc
,
434 old_x
,old_y
,attr
.width
-1,attr
.height
-1);
439 /* Compute new coordinates. */
440 x
=attr
.x
+(ev
.xmotion
.x
-grab_x
);
441 y
=attr
.y
+(ev
.xmotion
.y
-grab_y
);
443 x
=((x
+attr
.width
)<screen_width
)?x
:screen_width
-attr
.width
;
444 y
=((y
+attr
.height
)<screen_height
)?y
:screen_height
-attr
.height
;
447 /* Draw rectangles: we use a GCxor function for
448 not having to remember background data. */
449 if (x
!=old_x
|| y
!=old_y
) {
450 XDrawRectangle(display
,root
,gc
,
451 old_x
,old_y
,attr
.width
-1,attr
.height
-1);
452 XDrawRectangle(display
,root
,gc
,
453 x
,y
,attr
.width
-1,attr
.height
-1);
455 /* Save coordinates */
460 XUngrabPointer(display
,0);
461 if(old_x
!=params
->x
|| old_y
!=params
->y
)
462 result
=XMoveWindow(display
,window
,x
,y
);
464 /* Save new coordinates if it changed, remap the window otherwize */
465 if(old_x
!=params
->x
||old_y
!=params
->y
) {
469 XMapWindow(display
,window
);
475 /*----------------------------------------------------------------------------*/
477 xwindow_resize_window(Display
* display
, Window window
, cfgfile_item
* item
,
478 int width
, int height
, int force_update
)
481 uint screen_width
, screen_height
;
483 XWindowAttributes attr
;
485 if (!(display
&& window
)) return 0;
487 if (width
>0 && height
>=0)
488 if(XGetWindowAttributes(display
, window
, &attr
))
489 if (force_update
|| width
!=attr
.width
|| height
!=attr
.height
) {
490 if (attr
.override_redirect
) {
491 /* Unmanaged window: boundaries check */
492 screen_width
=WidthOfScreen(ScreenOfDisplay(display
,item
->scr
));
493 screen_height
=HeightOfScreen(ScreenOfDisplay(display
,item
->scr
));
496 x
=(x
+width
>screen_width
)?screen_width
-width
:x
;
497 y
=(y
+height
>screen_height
)?screen_height
-height
:y
;
500 if (XMoveResizeWindow(display
,window
,
501 x
,y
,(uint
)width
,(uint
)height
))
504 /* Managed window: no boundary check */
505 xwindow_error_reset();
506 XResizeWindow(display
,window
,(uint
)width
,(uint
)height
);
507 if(xwindow_error_check()) {
508 /* WM_Hints settings */
509 if ((hints
=XAllocSizeHints())) {
510 hints
->min_width
=hints
->max_width
=(uint
)width
;
511 hints
->min_height
=hints
->max_height
=(uint
)height
;
512 hints
->flags
=PMinSize
|PMaxSize
;
513 XSetWMNormalHints(display
,window
,hints
);
523 #ifdef WM_DETECTION_OLD_STYLE
524 /*----------------------------------------------------------------------------*/
525 /* Here is a function that recursively calls itself (up to a limit) to find
526 the window ID of the KDE desktop to draw on. This is the hierarchy we're
530 0 -> window with name="KDE Desktop"
531 1 -> window with no name
532 2 -> window with name="KDE Desktop" & _NET_WM_WINDOW_TYPE_DESKTOP
533 3 -> window with no name and width >= width of screen
535 The last window in the hierarchy is the one to draw to. The
536 numbers show the value of the `depth' argument.
538 NOTE: This code was copied from xpenguins source code base -
539 http://xpenguins.seul.org/
542 xwindow_get_kde_desktop(Display
*display
, int screen
, Window window
,
543 Atom atom
, char *atomname
, int depth
)
546 unsigned char *wintype
= NULL
;
547 Window winreturn
= 0;
548 unsigned long nitems
, bytesafter
;
551 Window rootReturn
, parentReturn
, *children
;
552 unsigned int nChildren
;
554 if (XFetchName(display
, window
, &name
)) {
555 if (strcasecmp(name
, "KDE Desktop") == 0) {
556 /* Presumably either at depth 0 or 2 */
557 if (XGetWindowProperty(display
, window
, atom
, 0, 1,
559 &actual_type
, &actual_format
,
560 &nitems
, &bytesafter
,
563 char *tmpatomname
= XGetAtomName(display
, *((Atom
*)wintype
));
565 if (strcmp(atomname
, tmpatomname
) == 0 && depth
== 2) {
569 XFree((char *) tmpatomname
);
572 else if (depth
< 2) {
576 else if (depth
== 1) {
579 XFree((char *) name
);
581 else if (depth
== 1) {
584 /* If go_deeper is 1 then there is a possibility that the background
585 * window is a descendant of the current window; otherwise we're
586 * barking up the wrong tree. */
587 if (go_deeper
&& XQueryTree(display
, window
, &rootReturn
,
588 &parentReturn
, &children
,
591 for (i
= 0; i
< nChildren
; ++i
) {
592 /* children[i] is now at depth 3 */
594 XWindowAttributes attributes
;
595 if (XGetWindowAttributes(display
, children
[i
], &attributes
)) {
596 if (attributes
.width
>= DisplayWidth(display
, screen
)/2
597 && attributes
.height
> 0) {
599 winreturn
= children
[i
];
604 else if ((winreturn
= xwindow_get_kde_desktop(display
, screen
,
611 XFree((char *) children
);
616 /*----------------------------------------------------------------------------*/
617 /* Looks for the Nautilus desktop window to draw to, given the toplevel
618 window of the Nautilus desktop. Basically recursively calls itself
619 looking for subwindows the same size as the root window.
621 NOTE: This code was copied verbatim from xpenguins-2.2 source code base -
622 http://xpenguins.seul.org/
625 xwindow_get_nautilus_desktop(Display
*display
, int screen
, Window window
,
628 Window rootReturn
, parentReturn
, *children
;
629 Window winreturn
= window
;
630 unsigned int nChildren
;
635 else if (XQueryTree(display
, window
, &rootReturn
, &parentReturn
,
636 &children
, &nChildren
)) {
638 for (i
= 0; i
< nChildren
; ++i
) {
639 XWindowAttributes attributes
;
640 if (XGetWindowAttributes(display
, children
[i
], &attributes
)) {
641 if (attributes
.width
== DisplayWidth(display
, screen
)
642 && attributes
.height
== DisplayHeight(display
, screen
)) {
643 /* Found a possible desktop window */
644 winreturn
= xwindow_get_nautilus_desktop(display
, screen
,
645 children
[i
], depth
+1);
649 XFree((char *) children
);
653 #endif /* WM_DETECTION_OLD_STYLE */
655 /*----------------------------------------------------------------------------*/
656 /* Returns the root window, or the fake root window depending on
657 WM. Autodetect fake root for Xfce4, nautilus and KDE.
660 xwindow_get_root_window(Display
* display
, int scr
)
662 #ifdef WM_DETECTION_OLD_STYLE
665 Window rootReturn
, parentReturn
, *children
;
666 unsigned int nChildren
;
668 Window root
= RootWindow(display
,scr
),
671 NAUTILUS_DESKTOP_WINDOW_ID
= XInternAtom(display
,
672 "NAUTILUS_DESKTOP_WINDOW_ID",
675 if (XGetWindowProperty(display
, root
,
676 NAUTILUS_DESKTOP_WINDOW_ID
,
677 0, 1, False
, XA_WINDOW
,
679 (int*)((void*)&dummy
),
682 (unsigned char **)((void*)&toplevel
)) == Success
684 result
= xwindow_get_nautilus_desktop(display
,scr
,*toplevel
,0);
686 /* Next look for a virtual root or a KDE Desktop */
688 && XQueryTree(display
, root
, &rootReturn
, &parentReturn
,
689 &children
, &nChildren
)) {
690 Atom _NET_WM_WINDOW_TYPE
= XInternAtom(display
,
691 "_NET_WM_WINDOW_TYPE",
693 Atom __SWM_VROOT
= XInternAtom(display
, "__SWM_VROOT", False
);
695 for (i
=0; i
<nChildren
&& !result
; ++i
) {
696 Window
*toplevel
= (Window
*) 0;
697 if (XGetWindowProperty(display
, children
[i
],
698 __SWM_VROOT
, 0, 1, False
, XA_WINDOW
,
699 &TYPE
, (int*) ((void*)&dummy
),
701 (unsigned char **)((void*)&toplevel
)) == Success
707 result
= xwindow_get_kde_desktop(display
, scr
, children
[i
],
709 "_NET_WM_WINDOW_TYPE_DESKTOP",
712 XFree((char *) children
);
715 return (result
)?result
:root
;
719 XWindowAttributes xattr
;
721 /* Try reading the ADESKLETS_ROOT environment variable to identify the root */
722 if ((root_env
=getenv("ADESKLETS_ROOT")) &&
723 sscanf(root_env
,"%x", &window
)==1)
724 if (XGetWindowAttributes(display
, (Window
)window
, &xattr
)==0) {
725 debug("Invalid 0x%x Windows given as root!", window
);
729 /* Use the specified window as root, or the real root otherwise */
730 return (window
)?(Window
)window
:RootWindow(display
, scr
);
731 #endif /* WM_DETECTION_OLD_STYLE */
734 #endif /* X_MISSING_DISPLAY , far, far above! */
736 /*----------------------------------------------------------------------------*/
737 /* Save selected elements of imlib2 context for future restoration.
738 Note: This uses a vector `contextes' of context_backup references,
739 used like a stack (last-in, first-out): this lead to correct
740 recursive call of the function pairs xwindow_context_save().
741 and xwindow_context_restore().
744 xwindow_context_save(long mycontext
)
746 context_backup
* context
;
748 /* Contextes initialisation */
749 if(!contextes
&& (!(contextes
=vector_init()))) {
750 debug("Error initialising contexes!\n");
754 /* New context initialisation */
755 if(!(context
=(context_backup
*)malloc(sizeof(context_backup
)))) {
756 debug("Error initialising new context!\n");
760 /* Save present context */
761 context
->context
=mycontext
;
763 #ifdef X_DISPLAY_MISSING
764 mycontext
&=~(IMLIB_DISPLAY
|IMLIB_VISUAL
|IMLIB_COLORMAP
|IMLIB_DRAWABLE
|
765 IMLIB_MASK
|IMLIB_DITHER_MASK
);
768 /* Most frequently saved items are traited first, for optimisation sake */
769 #define CONTEXT_ACTION(mask, x ) \
770 if(mycontext&(mask)) {\
773 if(!(mycontext&=~(mask))) goto end_of_context_save
775 CONTEXT_ACTION(IMLIB_IMAGE
,
776 context
->image
=imlib_context_get_image());
777 CONTEXT_ACTION(IMLIB_COLOR
,
778 imlib_context_get_color(&context
->red
,
782 CONTEXT_ACTION(IMLIB_BLEND
,
783 context
->blend
=imlib_context_get_blend());
784 CONTEXT_ACTION(IMLIB_FONT
,
785 context
->font
=imlib_context_get_font());
786 CONTEXT_ACTION(IMLIB_OPERATION
,
787 context
->operation
=imlib_context_get_operation());
788 CONTEXT_ACTION(IMLIB_COLOR_RANGE
,
789 context
->color_range
=imlib_context_get_color_range());
790 CONTEXT_ACTION(IMLIB_FILTER
,
791 context
->filter
=imlib_context_get_filter());
792 #ifndef X_DISPLAY_MISSING
793 CONTEXT_ACTION(IMLIB_DISPLAY
,
794 context
->display
=imlib_context_get_display());
795 CONTEXT_ACTION(IMLIB_VISUAL
,
796 context
->visual
=imlib_context_get_visual());
797 CONTEXT_ACTION(IMLIB_COLORMAP
,
798 context
->colormap
=imlib_context_get_colormap());
799 CONTEXT_ACTION(IMLIB_DRAWABLE
,
800 context
->drawable
=imlib_context_get_drawable());
801 CONTEXT_ACTION(IMLIB_MASK
,
802 context
->mask
=imlib_context_get_mask());
803 CONTEXT_ACTION(IMLIB_DITHER_MASK
,
804 context
->dither_mask
=imlib_context_get_dither_mask());
806 CONTEXT_ACTION(IMLIB_ANTI_ALIAS
,
807 context
->anti_alias
=imlib_context_get_anti_alias());
808 CONTEXT_ACTION(IMLIB_DITHER
,
809 context
->dither
=imlib_context_get_dither());
810 CONTEXT_ACTION(IMLIB_COLOR_MODIFIER
,
811 context
->color_modifier
=
812 imlib_context_get_color_modifier());
813 CONTEXT_ACTION(IMLIB_DIRECTION
,
814 context
->direction
=imlib_context_get_direction());
815 CONTEXT_ACTION(IMLIB_ANGLE
,
816 context
->angle
=imlib_context_get_angle());
817 #undef CONTEXT_ACTION
819 /* This code should never be reached ! */
820 debug("Error in creating new context!\n");
823 vector_push(contextes
,context
);
826 /*----------------------------------------------------------------------------*/
827 /* Restore a given imlib context, somewhere after a call
828 to xwindow_context_save */
830 xwindow_context_restore(void)
832 context_backup
* context
;
834 /* Verify there is comething to restore */
835 if(!contextes
|| !contextes
->pos
) {
836 debug("No context to restore!\n");
840 /* Commodity setting */
841 context
=(context_backup
*)contextes
->content
[contextes
->pos
-1];
843 /* Most frequently saved items are traited first, for optimisation sake */
844 #define CONTEXT_ACTION(mask, x ) \
845 if(context->context&(mask)) {\
848 if(!(context->context&=~(mask))) goto end_of_restore_context
850 CONTEXT_ACTION(IMLIB_IMAGE
,
851 imlib_context_set_image(context
->image
));
852 CONTEXT_ACTION(IMLIB_COLOR
,
853 imlib_context_set_color(context
->red
,
857 CONTEXT_ACTION(IMLIB_BLEND
,
858 imlib_context_set_blend(context
->blend
));
859 CONTEXT_ACTION(IMLIB_FONT
,
860 imlib_context_set_font(context
->font
));
861 CONTEXT_ACTION(IMLIB_OPERATION
,
862 imlib_context_set_operation(context
->operation
));
863 CONTEXT_ACTION(IMLIB_COLOR_RANGE
,
864 imlib_context_set_color_range(context
->color_range
));
865 CONTEXT_ACTION(IMLIB_FILTER
,
866 imlib_context_set_filter(context
->filter
));
867 #ifndef X_DISPLAY_MISSING
868 CONTEXT_ACTION(IMLIB_DISPLAY
,
869 imlib_context_set_display(context
->display
));
870 CONTEXT_ACTION(IMLIB_VISUAL
,
871 imlib_context_set_visual(context
->visual
));
872 CONTEXT_ACTION(IMLIB_COLORMAP
,
873 imlib_context_set_colormap(context
->colormap
));
874 CONTEXT_ACTION(IMLIB_DRAWABLE
,
875 imlib_context_set_drawable(context
->drawable
));
876 CONTEXT_ACTION(IMLIB_MASK
,
877 imlib_context_set_mask(context
->mask
));
878 CONTEXT_ACTION(IMLIB_DITHER_MASK
,
879 imlib_context_set_dither_mask(context
->dither_mask
));
881 CONTEXT_ACTION(IMLIB_ANTI_ALIAS
,
882 imlib_context_set_anti_alias(context
->anti_alias
));
883 CONTEXT_ACTION(IMLIB_DITHER
,
884 imlib_context_set_dither(context
->dither
));
885 CONTEXT_ACTION(IMLIB_COLOR_MODIFIER
,
886 imlib_context_set_color_modifier(context
->color_modifier
));
887 CONTEXT_ACTION(IMLIB_DIRECTION
,
888 imlib_context_set_direction(context
->direction
));
889 CONTEXT_ACTION(IMLIB_ANGLE
,
890 imlib_context_set_angle(context
->angle
));
891 #undef CONTEXT_ACTION
893 /* This code should never be reached ! */
894 debug("Error restoring context!\n");
896 end_of_restore_context
:
897 vector_pop(contextes
);
899 contextes
=vector_free(contextes
);