1 /*--- xwindow.c ----------------------------------------------------------------
2 Copyright (C) 2004, 2005, 2006 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
));
127 #ifdef HAVE_FONTCONFIG_FCFINI
130 /* On FontConfig >= 2.4, this causes a segfault, probably due to the new
131 caching mechanism: we don't have to care, since FcFini() always exists,
132 and does the dirty dessalocation job just fine.
134 if (fs
) FcFontSetDestroy(fs
);
135 FcObjectSetDestroy(os
);
139 imlib_add_path_to_font_path(".");
141 imlib_add_path_to_font_path("../sharedata");
145 /*----------------------------------------------------------------------------*/
146 #ifndef X_DISPLAY_MISSING
149 xwindow_non_fatal_error_handler(Display
* display
, XErrorEvent
* ev
)
153 if(!display
) return 0;
155 /* Print out error description */
156 if (!XGetErrorText(display
,ev
->error_code
,buffer
,sizeof(buffer
)))
157 fprintf(stderr
,"Error: with X protocol on display `%s'\n%s\n",
158 XDisplayName(NULL
),buffer
);
159 /* Save error description */
160 memcpy(&xerror_event
,ev
,sizeof(XErrorEvent
));
164 /*----------------------------------------------------------------------------*/
166 xwindow_error_reset(void)
168 memset(&xerror_event
,0,sizeof(XErrorEvent
));
171 /*----------------------------------------------------------------------------*/
173 xwindow_error_check(void)
175 return xerror_event
.error_code
==0;
178 /*----------------------------------------------------------------------------*/
179 /* Sends back dimensions of given window. */
181 xwindow_window_size(Display
* display
, Window window
,
182 uint
* width_return
, uint
* height_return
)
186 return display
&& window
&&
187 XGetGeometry(display
, window
, &root
,
188 &dummy
, &dummy
, width_return
, height_return
,
189 (uint
*)&dummy
,(uint
*)&dummy
);
192 /*----------------------------------------------------------------------------*/
193 /* Return 1 if given coordinates changed since last call.
194 Note: only works with one set of coordinates */
196 xwindow_window_moved_or_resized(int new_x
, int new_y
,
197 int new_width
, int new_height
)
199 static int x
=-1, y
=-1, width
=-1, height
=-1;
201 result
=!(x
==new_x
&& y
==new_y
&& width
==new_width
&& height
==new_height
);
202 x
=new_x
;y
=new_y
;width
=new_width
;height
=new_height
;
206 /*----------------------------------------------------------------------------*/
207 /* Returns 1 if background has changed since last call, 0 otherwise.
208 This is enlightment mechanism. Go read:
209 http://gershwin.ens.fr/vdaniel/Doc-Locale/Outils-Gnu-Linux/Eterm-0.9/#trans
210 NOTE: this will always returns 0 when this mechanism is not supported.
213 xwindow_updated_background(Display
* display
, Window root
, Atom id
)
216 static Pixmap old_pixmap
= None
;
217 Pixmap pixmap
= None
;
220 unsigned long nitems
, bytes_after
;
221 unsigned char *prop
= NULL
;
223 if (!(display
&& root
)) return 0;
225 if(id
==None
) id
=XInternAtom(display
,"_XROOTPMAP_ID", True
);
227 XGetWindowProperty(display
, root
, id
, 0, 1, False
, XA_PIXMAP
,
228 &act_type
, &act_format
, &nitems
, &bytes_after
,
231 pixmap
= *((Pixmap
*)prop
);
232 result
=(old_pixmap
!=pixmap
);
240 /*----------------------------------------------------------------------------*/
241 /* Routine to grab the background in Imlib_Image.
242 Returns NULL if it fails, Reference to output Imlib_Image otherwise.
245 xwindow_grab_background(Display
* display
, int screen
, Window window
)
250 XWindowAttributes attr
;
251 Imlib_Image background
=NULL
;
253 if (!(display
&& window
)) return NULL
;
255 if(XGetWindowAttributes(display
,window
,&attr
) &&
256 /* Avoid reparenting coordinates translation problem */
257 XTranslateCoordinates(display
,window
,RootWindow(display
,screen
),
258 0, 0, &x
, &y
, &src
)) {
259 /* The trick is to create an Overrideredirect window overlapping our
260 window with background type of Parent relative and then grab it.
261 It seems overkill, but:
262 - XGetImage() on root get all viewable children windows embedded.
263 - XCopyArea() cause potential synchronisation problems depending
264 on backing store settings of root window: playing around
265 with GraphicsExpose events is not quicker nor simpler.
267 This idea was taken from aterm source base. See src/pixmap.c
268 in core distribution (http://aterm.sourceforge.net/).
270 if((src
=XCreateWindow(display
,
271 RootWindow(display
,screen
),
272 x
, y
, attr
.width
, attr
.height
,
274 CopyFromParent
, CopyFromParent
, CopyFromParent
,
275 CWBackPixmap
|CWBackingStore
|
276 CWOverrideRedirect
|CWEventMask
,
277 &XDefaultWindowAttributes
))) {
278 xwindow_context_save(IMLIB_DRAWABLE
|IMLIB_IMAGE
);
279 XGrabServer(display
);
280 XMapRaised(display
,src
);
281 XSync(display
,False
);
283 XWindowEvent(display
, src
, ExposureMask
, &ev
);
284 while(ev
.type
!=Expose
);
285 imlib_context_set_drawable(src
);
286 background
=imlib_create_image_from_drawable(0,0,0,
287 attr
.width
,attr
.height
,0);
288 XUngrabServer(display
);
289 XDestroyWindow(display
,src
);
291 /* Make sure image has an alpha channel */
292 imlib_context_set_image(background
);
293 imlib_image_set_has_alpha(1);
295 /* Restore context */
296 xwindow_context_restore();
302 /*----------------------------------------------------------------------------*/
303 /* Redraw updates rectangles onto window by copying background image at same
307 xwindow_update_window(Window window
, Imlib_Updates
* updates
,
308 Imlib_Image background
, Imlib_Image foreground
,
309 int transparency_flag
)
311 int x
,y
,width
,height
;
313 Imlib_Updates update
;
315 /* Verify there is something to update */
316 if(window
&& *updates
) {
317 /* Save context states */
318 xwindow_context_save(IMLIB_IMAGE
|IMLIB_COLOR
|IMLIB_OPERATION
|
319 IMLIB_BLEND
|IMLIB_COLOR_MODIFIER
|IMLIB_FILTER
|
322 /* Pre-loop settings */
323 imlib_context_set_drawable(window
);
324 imlib_context_set_blend(0);
325 imlib_context_set_color_modifier(NULL
);
326 imlib_context_set_filter(NULL
);
327 if(transparency_flag
) {
328 imlib_context_set_operation(IMLIB_OP_COPY
);
330 imlib_context_set_image(foreground
);
332 /* Loop over updates */
335 update
=imlib_updates_get_next(update
)) {
336 imlib_updates_get_coordinates(update
,&x
,&y
,(int*)&width
,(int*)&height
);
337 if (transparency_flag
) {
338 if((image
=imlib_create_image(width
,height
))) {
339 imlib_context_set_image(image
);
341 /* Make sur the alpha channel is detected */
342 imlib_image_set_has_alpha(1);
344 /* Fill image wih full opaque black, then copy
346 imlib_context_set_color(0,0,0,255);
347 imlib_image_fill_rectangle(0,0,width
,height
);
348 imlib_blend_image_onto_image(background
,0,
352 /* Blend foreground over background */
353 imlib_context_set_blend(1);
354 imlib_blend_image_onto_image(foreground
,1,
358 /* Copy image to drawable and free it */
359 imlib_context_set_blend(0);
360 imlib_render_image_on_drawable(x
,y
);
364 /* Otherwise, just copy foreground, without alteration */
365 imlib_render_image_part_on_drawable_at_size(x
,y
,width
,height
,
369 /* Restore initial context states */
370 xwindow_context_restore();
374 /*----------------------------------------------------------------------------*/
375 /* This move a window using outline rectangles if a window is mapped, and
376 updates cfgfile_item params accordingly. This is used by adesklets
377 if we created an `override_notify' window, and that therefore cannot take
378 advantage of any windows manager. Returns 1 if the window has been moved,
380 NOTE: The window is not remmaped at the end if the move was sucessfull:
381 it is the duty of the caller to do so.
384 xwindow_move_window(Display
* display
, Window root
, Window window
,
385 cfgfile_item
* params
)
387 int dummy
, grab_x
, grab_y
, old_x
, old_y
, x
=0, y
=0, result
=0;
388 uint screen_width
, screen_height
;
389 XWindowAttributes attr
;
396 if (!(display
&& window
)) return 0;
398 /* Test that main window is mapped,
399 and if screen size could be known */
400 if(XGetWindowAttributes(display
,window
,&attr
) &&
401 attr
.map_state
!=IsUnmapped
&&
402 xwindow_window_size(display
,root
,&screen_width
,&screen_height
)) {
403 /* Initialize a graphics context for the root window behind ours */
404 xgcvalues
.function
=GXxor
;
405 xgcvalues
.foreground
=WhitePixel(display
,params
->scr
);
406 xwindow_error_reset();
407 gc
=XCreateGC(display
,root
,GCFunction
|GCForeground
,&xgcvalues
);
408 /* Initialize cursor */
409 cursor
= XCreateFontCursor(display
,XC_fleur
);
410 /* Initialize old coordinates */
411 old_x
=attr
.x
; old_y
=attr
.y
;
412 /* Unmap the window */
413 if (xwindow_error_check() &&
414 XUnmapWindow(display
,window
)) {
415 /* Query, then grab the pointer */
416 if(XQueryPointer(display
, window
, &dummy_window
,
417 &dummy_window
, &grab_x
, &grab_y
,
418 &dummy
, &dummy
, (uint
*)&dummy
) &&
419 XGrabPointer(display
,root
,True
,
420 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
421 GrabModeAsync
,GrabModeAsync
,
422 root
, cursor
, 0)==GrabSuccess
) {
423 /* Draw initial rectangle */
424 XDrawRectangle(display
,root
,gc
,
425 attr
.x
,attr
.y
,attr
.width
-1,attr
.height
-1);
428 XWindowEvent(display
,root
,
429 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
436 /* We want a button press in our window before we take
437 this into account: the idea is that we want to ignore
438 button release event from menu */
440 /* Erase final rectangle */
441 XDrawRectangle(display
,root
,gc
,
442 old_x
,old_y
,attr
.width
-1,attr
.height
-1);
447 /* Compute new coordinates. */
448 x
=attr
.x
+(ev
.xmotion
.x
-grab_x
);
449 y
=attr
.y
+(ev
.xmotion
.y
-grab_y
);
451 x
=((x
+attr
.width
)<screen_width
)?x
:screen_width
-attr
.width
;
452 y
=((y
+attr
.height
)<screen_height
)?y
:screen_height
-attr
.height
;
455 /* Draw rectangles: we use a GCxor function for
456 not having to remember background data. */
457 if ((x
!=old_x
) || (y
!=old_y
)) {
458 XDrawRectangle(display
,root
,gc
,
459 old_x
,old_y
,attr
.width
-1,attr
.height
-1);
460 XDrawRectangle(display
,root
,gc
,
461 x
,y
,attr
.width
-1,attr
.height
-1);
463 /* Save coordinates */
468 XUngrabPointer(display
,0);
469 if(old_x
!=params
->x
|| old_y
!=params
->y
)
470 result
=XMoveWindow(display
,window
,x
,y
);
472 /* Save new coordinates if it changed, remap the window otherwize */
473 if(old_x
!=params
->x
||old_y
!=params
->y
) {
477 XMapWindow(display
,window
);
483 /*----------------------------------------------------------------------------*/
485 xwindow_resize_window(Display
* display
, Window window
, cfgfile_item
* item
,
486 int width
, int height
, int force_update
)
489 uint screen_width
, screen_height
;
491 XWindowAttributes attr
;
493 if (!(display
&& window
)) return 0;
495 if (width
>0 && height
>=0 && XGetWindowAttributes(display
, window
, &attr
)) {
496 if (force_update
|| width
!=attr
.width
|| height
!=attr
.height
) {
497 if (attr
.override_redirect
) {
498 /* Unmanaged window: boundaries check */
499 screen_width
=WidthOfScreen(ScreenOfDisplay(display
,item
->scr
));
500 screen_height
=HeightOfScreen(ScreenOfDisplay(display
,item
->scr
));
503 x
=(x
+width
>screen_width
)?screen_width
-width
:x
;
504 y
=(y
+height
>screen_height
)?screen_height
-height
:y
;
507 if (XMoveResizeWindow(display
,window
,
508 x
,y
,(uint
)width
,(uint
)height
))
511 /* Managed window: no boundary check */
512 xwindow_error_reset();
513 XResizeWindow(display
,window
,(uint
)width
,(uint
)height
);
514 if(xwindow_error_check()) {
515 /* WM_Hints settings */
516 if ((hints
=XAllocSizeHints())) {
517 hints
->min_width
=hints
->max_width
=(uint
)width
;
518 hints
->min_height
=hints
->max_height
=(uint
)height
;
519 hints
->flags
=PMinSize
|PMaxSize
;
520 XSetWMNormalHints(display
,window
,hints
);
527 if (!force_update
) result
=1;
532 #ifdef WM_DETECTION_OLD_STYLE
533 /*----------------------------------------------------------------------------*/
534 /* Here is a function that recursively calls itself (up to a limit) to find
535 the window ID of the KDE desktop to draw on. This is the hierarchy we're
539 0 -> window with name="KDE Desktop"
540 1 -> window with no name
541 2 -> window with name="KDE Desktop" & _NET_WM_WINDOW_TYPE_DESKTOP
542 3 -> window with no name and width >= width of screen
544 The last window in the hierarchy is the one to draw to. The
545 numbers show the value of the `depth' argument.
547 NOTE: This code was copied from xpenguins source code base -
548 http://xpenguins.seul.org/
551 xwindow_get_kde_desktop(Display
*display
, int screen
, Window window
,
552 Atom atom
, char *atomname
, int depth
)
555 unsigned char *wintype
= NULL
;
556 Window winreturn
= 0;
557 unsigned long nitems
, bytesafter
;
560 Window rootReturn
, parentReturn
, *children
;
561 unsigned int nChildren
;
563 if (XFetchName(display
, window
, &name
)) {
564 if (strcasecmp(name
, "KDE Desktop") == 0) {
565 /* Presumably either at depth 0 or 2 */
566 if (XGetWindowProperty(display
, window
, atom
, 0, 1,
568 &actual_type
, &actual_format
,
569 &nitems
, &bytesafter
,
572 char *tmpatomname
= XGetAtomName(display
, *((Atom
*)wintype
));
574 if (strcmp(atomname
, tmpatomname
) == 0 && depth
== 2) {
578 XFree((char *) tmpatomname
);
581 else if (depth
< 2) {
585 else if (depth
== 1) {
588 XFree((char *) name
);
590 else if (depth
== 1) {
593 /* If go_deeper is 1 then there is a possibility that the background
594 * window is a descendant of the current window; otherwise we're
595 * barking up the wrong tree. */
596 if (go_deeper
&& XQueryTree(display
, window
, &rootReturn
,
597 &parentReturn
, &children
,
600 for (i
= 0; i
< nChildren
; ++i
) {
601 /* children[i] is now at depth 3 */
603 XWindowAttributes attributes
;
604 if (XGetWindowAttributes(display
, children
[i
], &attributes
)) {
605 if (attributes
.width
>= DisplayWidth(display
, screen
)/2
606 && attributes
.height
> 0) {
608 winreturn
= children
[i
];
613 else if ((winreturn
= xwindow_get_kde_desktop(display
, screen
,
620 XFree((char *) children
);
625 /*----------------------------------------------------------------------------*/
626 /* Looks for the Nautilus desktop window to draw to, given the toplevel
627 window of the Nautilus desktop. Basically recursively calls itself
628 looking for subwindows the same size as the root window.
630 NOTE: This code was copied verbatim from xpenguins-2.2 source code base -
631 http://xpenguins.seul.org/
634 xwindow_get_nautilus_desktop(Display
*display
, int screen
, Window window
,
637 Window rootReturn
, parentReturn
, *children
;
638 Window winreturn
= window
;
639 unsigned int nChildren
;
644 else if (XQueryTree(display
, window
, &rootReturn
, &parentReturn
,
645 &children
, &nChildren
)) {
647 for (i
= 0; i
< nChildren
; ++i
) {
648 XWindowAttributes attributes
;
649 if (XGetWindowAttributes(display
, children
[i
], &attributes
)) {
650 if (attributes
.width
== DisplayWidth(display
, screen
)
651 && attributes
.height
== DisplayHeight(display
, screen
)) {
652 /* Found a possible desktop window */
653 winreturn
= xwindow_get_nautilus_desktop(display
, screen
,
654 children
[i
], depth
+1);
658 XFree((char *) children
);
662 #endif /* WM_DETECTION_OLD_STYLE */
664 /*----------------------------------------------------------------------------*/
665 /* Returns the root window, or the fake root window depending on
666 WM. Autodetect fake root for Xfce4, nautilus and KDE.
669 xwindow_get_root_window(Display
* display
, int scr
)
671 #ifdef WM_DETECTION_OLD_STYLE
674 Window rootReturn
, parentReturn
, *children
;
675 unsigned int nChildren
;
677 Window root
= RootWindow(display
,scr
),
680 NAUTILUS_DESKTOP_WINDOW_ID
= XInternAtom(display
,
681 "NAUTILUS_DESKTOP_WINDOW_ID",
684 if (XGetWindowProperty(display
, root
,
685 NAUTILUS_DESKTOP_WINDOW_ID
,
686 0, 1, False
, XA_WINDOW
,
688 (int*)((void*)&dummy
),
691 (unsigned char **)((void*)&toplevel
)) == Success
693 result
= xwindow_get_nautilus_desktop(display
,scr
,*toplevel
,0);
695 /* Next look for a virtual root or a KDE Desktop */
697 && XQueryTree(display
, root
, &rootReturn
, &parentReturn
,
698 &children
, &nChildren
)) {
699 Atom _NET_WM_WINDOW_TYPE
= XInternAtom(display
,
700 "_NET_WM_WINDOW_TYPE",
702 Atom __SWM_VROOT
= XInternAtom(display
, "__SWM_VROOT", False
);
704 for (i
=0; i
<nChildren
&& !result
; ++i
) {
705 Window
*toplevel
= (Window
*) 0;
706 if (XGetWindowProperty(display
, children
[i
],
707 __SWM_VROOT
, 0, 1, False
, XA_WINDOW
,
708 &TYPE
, (int*) ((void*)&dummy
),
710 (unsigned char **)((void*)&toplevel
)) == Success
716 result
= xwindow_get_kde_desktop(display
, scr
, children
[i
],
718 "_NET_WM_WINDOW_TYPE_DESKTOP",
721 XFree((char *) children
);
724 return (result
)?result
:root
;
728 XWindowAttributes xattr
;
730 /* Try reading the ADESKLETS_ROOT environment variable to identify the root */
731 if ((root_env
=getenv("ADESKLETS_ROOT")) &&
732 sscanf(root_env
,"%x", &window
)==1)
733 if (XGetWindowAttributes(display
, (Window
)window
, &xattr
)==0) {
734 debug("Invalid 0x%x Windows given as root!", window
);
738 /* Use the specified window as root, or the real root otherwise */
739 return (window
)?(Window
)window
:RootWindow(display
, scr
);
740 #endif /* WM_DETECTION_OLD_STYLE */
743 #endif /* X_MISSING_DISPLAY , far, far above! */
745 /*----------------------------------------------------------------------------*/
746 /* Save selected elements of imlib2 context for future restoration.
747 Note: This uses a vector `contextes' of context_backup references,
748 used like a stack (last-in, first-out): this lead to correct
749 recursive call of the function pairs xwindow_context_save().
750 and xwindow_context_restore().
753 xwindow_context_save(long mycontext
)
755 context_backup
* context
;
757 /* Contextes initialisation */
758 if(!contextes
&& (!(contextes
=vector_init()))) {
759 debug("Error initialising contexes!\n");
763 /* New context initialisation */
764 if(!(context
=(context_backup
*)malloc(sizeof(context_backup
)))) {
765 debug("Error initialising new context!\n");
769 /* Save present context */
770 context
->context
=mycontext
;
772 #ifdef X_DISPLAY_MISSING
773 mycontext
&=~(IMLIB_DISPLAY
|IMLIB_VISUAL
|IMLIB_COLORMAP
|IMLIB_DRAWABLE
|
774 IMLIB_MASK
|IMLIB_DITHER_MASK
);
777 /* Most frequently saved items are traited first, for optimisation sake */
778 #define CONTEXT_ACTION(mask, x ) \
779 if(mycontext&(mask)) {\
782 if(!(mycontext&=~(mask))) goto end_of_context_save
784 CONTEXT_ACTION(IMLIB_IMAGE
,
785 context
->image
=imlib_context_get_image());
786 CONTEXT_ACTION(IMLIB_COLOR
,
787 imlib_context_get_color(&context
->red
,
791 CONTEXT_ACTION(IMLIB_BLEND
,
792 context
->blend
=imlib_context_get_blend());
793 CONTEXT_ACTION(IMLIB_FONT
,
794 context
->font
=imlib_context_get_font());
795 CONTEXT_ACTION(IMLIB_OPERATION
,
796 context
->operation
=imlib_context_get_operation());
797 CONTEXT_ACTION(IMLIB_COLOR_RANGE
,
798 context
->color_range
=imlib_context_get_color_range());
799 CONTEXT_ACTION(IMLIB_FILTER
,
800 context
->filter
=imlib_context_get_filter());
801 #ifndef X_DISPLAY_MISSING
802 CONTEXT_ACTION(IMLIB_DISPLAY
,
803 context
->display
=imlib_context_get_display());
804 CONTEXT_ACTION(IMLIB_VISUAL
,
805 context
->visual
=imlib_context_get_visual());
806 CONTEXT_ACTION(IMLIB_COLORMAP
,
807 context
->colormap
=imlib_context_get_colormap());
808 CONTEXT_ACTION(IMLIB_DRAWABLE
,
809 context
->drawable
=imlib_context_get_drawable());
810 CONTEXT_ACTION(IMLIB_MASK
,
811 context
->mask
=imlib_context_get_mask());
812 CONTEXT_ACTION(IMLIB_DITHER_MASK
,
813 context
->dither_mask
=imlib_context_get_dither_mask());
815 CONTEXT_ACTION(IMLIB_ANTI_ALIAS
,
816 context
->anti_alias
=imlib_context_get_anti_alias());
817 CONTEXT_ACTION(IMLIB_DITHER
,
818 context
->dither
=imlib_context_get_dither());
819 CONTEXT_ACTION(IMLIB_COLOR_MODIFIER
,
820 context
->color_modifier
=
821 imlib_context_get_color_modifier());
822 CONTEXT_ACTION(IMLIB_DIRECTION
,
823 context
->direction
=imlib_context_get_direction());
824 CONTEXT_ACTION(IMLIB_ANGLE
,
825 context
->angle
=imlib_context_get_angle());
826 #undef CONTEXT_ACTION
828 /* This code should never be reached ! */
829 debug("Error in creating new context!\n");
832 vector_push(contextes
,context
);
835 /*----------------------------------------------------------------------------*/
836 /* Restore a given imlib context, somewhere after a call
837 to xwindow_context_save */
839 xwindow_context_restore(void)
841 context_backup
* context
;
843 /* Verify there is comething to restore */
844 if(!contextes
|| !contextes
->pos
) {
845 debug("No context to restore!\n");
849 /* Commodity setting */
850 context
=(context_backup
*)contextes
->content
[contextes
->pos
-1];
852 /* Most frequently saved items are traited first, for optimisation sake */
853 #define CONTEXT_ACTION(mask, x ) \
854 if(context->context&(mask)) {\
857 if(!(context->context&=~(mask))) goto end_of_restore_context
859 CONTEXT_ACTION(IMLIB_IMAGE
,
860 imlib_context_set_image(context
->image
));
861 CONTEXT_ACTION(IMLIB_COLOR
,
862 imlib_context_set_color(context
->red
,
866 CONTEXT_ACTION(IMLIB_BLEND
,
867 imlib_context_set_blend(context
->blend
));
868 CONTEXT_ACTION(IMLIB_FONT
,
869 imlib_context_set_font(context
->font
));
870 CONTEXT_ACTION(IMLIB_OPERATION
,
871 imlib_context_set_operation(context
->operation
));
872 CONTEXT_ACTION(IMLIB_COLOR_RANGE
,
873 imlib_context_set_color_range(context
->color_range
));
874 CONTEXT_ACTION(IMLIB_FILTER
,
875 imlib_context_set_filter(context
->filter
));
876 #ifndef X_DISPLAY_MISSING
877 CONTEXT_ACTION(IMLIB_DISPLAY
,
878 imlib_context_set_display(context
->display
));
879 CONTEXT_ACTION(IMLIB_VISUAL
,
880 imlib_context_set_visual(context
->visual
));
881 CONTEXT_ACTION(IMLIB_COLORMAP
,
882 imlib_context_set_colormap(context
->colormap
));
883 CONTEXT_ACTION(IMLIB_DRAWABLE
,
884 imlib_context_set_drawable(context
->drawable
));
885 CONTEXT_ACTION(IMLIB_MASK
,
886 imlib_context_set_mask(context
->mask
));
887 CONTEXT_ACTION(IMLIB_DITHER_MASK
,
888 imlib_context_set_dither_mask(context
->dither_mask
));
890 CONTEXT_ACTION(IMLIB_ANTI_ALIAS
,
891 imlib_context_set_anti_alias(context
->anti_alias
));
892 CONTEXT_ACTION(IMLIB_DITHER
,
893 imlib_context_set_dither(context
->dither
));
894 CONTEXT_ACTION(IMLIB_COLOR_MODIFIER
,
895 imlib_context_set_color_modifier(context
->color_modifier
));
896 CONTEXT_ACTION(IMLIB_DIRECTION
,
897 imlib_context_set_direction(context
->direction
));
898 CONTEXT_ACTION(IMLIB_ANGLE
,
899 imlib_context_set_angle(context
->angle
));
900 #undef CONTEXT_ACTION
902 /* This code should never be reached ! */
903 debug("Error restoring context!\n");
905 end_of_restore_context
:
906 vector_pop(contextes
);
908 contextes
=vector_free(contextes
);