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
);
520 if (!force_update
) result
=1;
524 #ifdef WM_DETECTION_OLD_STYLE
525 /*----------------------------------------------------------------------------*/
526 /* Here is a function that recursively calls itself (up to a limit) to find
527 the window ID of the KDE desktop to draw on. This is the hierarchy we're
531 0 -> window with name="KDE Desktop"
532 1 -> window with no name
533 2 -> window with name="KDE Desktop" & _NET_WM_WINDOW_TYPE_DESKTOP
534 3 -> window with no name and width >= width of screen
536 The last window in the hierarchy is the one to draw to. The
537 numbers show the value of the `depth' argument.
539 NOTE: This code was copied from xpenguins source code base -
540 http://xpenguins.seul.org/
543 xwindow_get_kde_desktop(Display
*display
, int screen
, Window window
,
544 Atom atom
, char *atomname
, int depth
)
547 unsigned char *wintype
= NULL
;
548 Window winreturn
= 0;
549 unsigned long nitems
, bytesafter
;
552 Window rootReturn
, parentReturn
, *children
;
553 unsigned int nChildren
;
555 if (XFetchName(display
, window
, &name
)) {
556 if (strcasecmp(name
, "KDE Desktop") == 0) {
557 /* Presumably either at depth 0 or 2 */
558 if (XGetWindowProperty(display
, window
, atom
, 0, 1,
560 &actual_type
, &actual_format
,
561 &nitems
, &bytesafter
,
564 char *tmpatomname
= XGetAtomName(display
, *((Atom
*)wintype
));
566 if (strcmp(atomname
, tmpatomname
) == 0 && depth
== 2) {
570 XFree((char *) tmpatomname
);
573 else if (depth
< 2) {
577 else if (depth
== 1) {
580 XFree((char *) name
);
582 else if (depth
== 1) {
585 /* If go_deeper is 1 then there is a possibility that the background
586 * window is a descendant of the current window; otherwise we're
587 * barking up the wrong tree. */
588 if (go_deeper
&& XQueryTree(display
, window
, &rootReturn
,
589 &parentReturn
, &children
,
592 for (i
= 0; i
< nChildren
; ++i
) {
593 /* children[i] is now at depth 3 */
595 XWindowAttributes attributes
;
596 if (XGetWindowAttributes(display
, children
[i
], &attributes
)) {
597 if (attributes
.width
>= DisplayWidth(display
, screen
)/2
598 && attributes
.height
> 0) {
600 winreturn
= children
[i
];
605 else if ((winreturn
= xwindow_get_kde_desktop(display
, screen
,
612 XFree((char *) children
);
617 /*----------------------------------------------------------------------------*/
618 /* Looks for the Nautilus desktop window to draw to, given the toplevel
619 window of the Nautilus desktop. Basically recursively calls itself
620 looking for subwindows the same size as the root window.
622 NOTE: This code was copied verbatim from xpenguins-2.2 source code base -
623 http://xpenguins.seul.org/
626 xwindow_get_nautilus_desktop(Display
*display
, int screen
, Window window
,
629 Window rootReturn
, parentReturn
, *children
;
630 Window winreturn
= window
;
631 unsigned int nChildren
;
636 else if (XQueryTree(display
, window
, &rootReturn
, &parentReturn
,
637 &children
, &nChildren
)) {
639 for (i
= 0; i
< nChildren
; ++i
) {
640 XWindowAttributes attributes
;
641 if (XGetWindowAttributes(display
, children
[i
], &attributes
)) {
642 if (attributes
.width
== DisplayWidth(display
, screen
)
643 && attributes
.height
== DisplayHeight(display
, screen
)) {
644 /* Found a possible desktop window */
645 winreturn
= xwindow_get_nautilus_desktop(display
, screen
,
646 children
[i
], depth
+1);
650 XFree((char *) children
);
654 #endif /* WM_DETECTION_OLD_STYLE */
656 /*----------------------------------------------------------------------------*/
657 /* Returns the root window, or the fake root window depending on
658 WM. Autodetect fake root for Xfce4, nautilus and KDE.
661 xwindow_get_root_window(Display
* display
, int scr
)
663 #ifdef WM_DETECTION_OLD_STYLE
666 Window rootReturn
, parentReturn
, *children
;
667 unsigned int nChildren
;
669 Window root
= RootWindow(display
,scr
),
672 NAUTILUS_DESKTOP_WINDOW_ID
= XInternAtom(display
,
673 "NAUTILUS_DESKTOP_WINDOW_ID",
676 if (XGetWindowProperty(display
, root
,
677 NAUTILUS_DESKTOP_WINDOW_ID
,
678 0, 1, False
, XA_WINDOW
,
680 (int*)((void*)&dummy
),
683 (unsigned char **)((void*)&toplevel
)) == Success
685 result
= xwindow_get_nautilus_desktop(display
,scr
,*toplevel
,0);
687 /* Next look for a virtual root or a KDE Desktop */
689 && XQueryTree(display
, root
, &rootReturn
, &parentReturn
,
690 &children
, &nChildren
)) {
691 Atom _NET_WM_WINDOW_TYPE
= XInternAtom(display
,
692 "_NET_WM_WINDOW_TYPE",
694 Atom __SWM_VROOT
= XInternAtom(display
, "__SWM_VROOT", False
);
696 for (i
=0; i
<nChildren
&& !result
; ++i
) {
697 Window
*toplevel
= (Window
*) 0;
698 if (XGetWindowProperty(display
, children
[i
],
699 __SWM_VROOT
, 0, 1, False
, XA_WINDOW
,
700 &TYPE
, (int*) ((void*)&dummy
),
702 (unsigned char **)((void*)&toplevel
)) == Success
708 result
= xwindow_get_kde_desktop(display
, scr
, children
[i
],
710 "_NET_WM_WINDOW_TYPE_DESKTOP",
713 XFree((char *) children
);
716 return (result
)?result
:root
;
720 XWindowAttributes xattr
;
722 /* Try reading the ADESKLETS_ROOT environment variable to identify the root */
723 if ((root_env
=getenv("ADESKLETS_ROOT")) &&
724 sscanf(root_env
,"%x", &window
)==1)
725 if (XGetWindowAttributes(display
, (Window
)window
, &xattr
)==0) {
726 debug("Invalid 0x%x Windows given as root!", window
);
730 /* Use the specified window as root, or the real root otherwise */
731 return (window
)?(Window
)window
:RootWindow(display
, scr
);
732 #endif /* WM_DETECTION_OLD_STYLE */
735 #endif /* X_MISSING_DISPLAY , far, far above! */
737 /*----------------------------------------------------------------------------*/
738 /* Save selected elements of imlib2 context for future restoration.
739 Note: This uses a vector `contextes' of context_backup references,
740 used like a stack (last-in, first-out): this lead to correct
741 recursive call of the function pairs xwindow_context_save().
742 and xwindow_context_restore().
745 xwindow_context_save(long mycontext
)
747 context_backup
* context
;
749 /* Contextes initialisation */
750 if(!contextes
&& (!(contextes
=vector_init()))) {
751 debug("Error initialising contexes!\n");
755 /* New context initialisation */
756 if(!(context
=(context_backup
*)malloc(sizeof(context_backup
)))) {
757 debug("Error initialising new context!\n");
761 /* Save present context */
762 context
->context
=mycontext
;
764 #ifdef X_DISPLAY_MISSING
765 mycontext
&=~(IMLIB_DISPLAY
|IMLIB_VISUAL
|IMLIB_COLORMAP
|IMLIB_DRAWABLE
|
766 IMLIB_MASK
|IMLIB_DITHER_MASK
);
769 /* Most frequently saved items are traited first, for optimisation sake */
770 #define CONTEXT_ACTION(mask, x ) \
771 if(mycontext&(mask)) {\
774 if(!(mycontext&=~(mask))) goto end_of_context_save
776 CONTEXT_ACTION(IMLIB_IMAGE
,
777 context
->image
=imlib_context_get_image());
778 CONTEXT_ACTION(IMLIB_COLOR
,
779 imlib_context_get_color(&context
->red
,
783 CONTEXT_ACTION(IMLIB_BLEND
,
784 context
->blend
=imlib_context_get_blend());
785 CONTEXT_ACTION(IMLIB_FONT
,
786 context
->font
=imlib_context_get_font());
787 CONTEXT_ACTION(IMLIB_OPERATION
,
788 context
->operation
=imlib_context_get_operation());
789 CONTEXT_ACTION(IMLIB_COLOR_RANGE
,
790 context
->color_range
=imlib_context_get_color_range());
791 CONTEXT_ACTION(IMLIB_FILTER
,
792 context
->filter
=imlib_context_get_filter());
793 #ifndef X_DISPLAY_MISSING
794 CONTEXT_ACTION(IMLIB_DISPLAY
,
795 context
->display
=imlib_context_get_display());
796 CONTEXT_ACTION(IMLIB_VISUAL
,
797 context
->visual
=imlib_context_get_visual());
798 CONTEXT_ACTION(IMLIB_COLORMAP
,
799 context
->colormap
=imlib_context_get_colormap());
800 CONTEXT_ACTION(IMLIB_DRAWABLE
,
801 context
->drawable
=imlib_context_get_drawable());
802 CONTEXT_ACTION(IMLIB_MASK
,
803 context
->mask
=imlib_context_get_mask());
804 CONTEXT_ACTION(IMLIB_DITHER_MASK
,
805 context
->dither_mask
=imlib_context_get_dither_mask());
807 CONTEXT_ACTION(IMLIB_ANTI_ALIAS
,
808 context
->anti_alias
=imlib_context_get_anti_alias());
809 CONTEXT_ACTION(IMLIB_DITHER
,
810 context
->dither
=imlib_context_get_dither());
811 CONTEXT_ACTION(IMLIB_COLOR_MODIFIER
,
812 context
->color_modifier
=
813 imlib_context_get_color_modifier());
814 CONTEXT_ACTION(IMLIB_DIRECTION
,
815 context
->direction
=imlib_context_get_direction());
816 CONTEXT_ACTION(IMLIB_ANGLE
,
817 context
->angle
=imlib_context_get_angle());
818 #undef CONTEXT_ACTION
820 /* This code should never be reached ! */
821 debug("Error in creating new context!\n");
824 vector_push(contextes
,context
);
827 /*----------------------------------------------------------------------------*/
828 /* Restore a given imlib context, somewhere after a call
829 to xwindow_context_save */
831 xwindow_context_restore(void)
833 context_backup
* context
;
835 /* Verify there is comething to restore */
836 if(!contextes
|| !contextes
->pos
) {
837 debug("No context to restore!\n");
841 /* Commodity setting */
842 context
=(context_backup
*)contextes
->content
[contextes
->pos
-1];
844 /* Most frequently saved items are traited first, for optimisation sake */
845 #define CONTEXT_ACTION(mask, x ) \
846 if(context->context&(mask)) {\
849 if(!(context->context&=~(mask))) goto end_of_restore_context
851 CONTEXT_ACTION(IMLIB_IMAGE
,
852 imlib_context_set_image(context
->image
));
853 CONTEXT_ACTION(IMLIB_COLOR
,
854 imlib_context_set_color(context
->red
,
858 CONTEXT_ACTION(IMLIB_BLEND
,
859 imlib_context_set_blend(context
->blend
));
860 CONTEXT_ACTION(IMLIB_FONT
,
861 imlib_context_set_font(context
->font
));
862 CONTEXT_ACTION(IMLIB_OPERATION
,
863 imlib_context_set_operation(context
->operation
));
864 CONTEXT_ACTION(IMLIB_COLOR_RANGE
,
865 imlib_context_set_color_range(context
->color_range
));
866 CONTEXT_ACTION(IMLIB_FILTER
,
867 imlib_context_set_filter(context
->filter
));
868 #ifndef X_DISPLAY_MISSING
869 CONTEXT_ACTION(IMLIB_DISPLAY
,
870 imlib_context_set_display(context
->display
));
871 CONTEXT_ACTION(IMLIB_VISUAL
,
872 imlib_context_set_visual(context
->visual
));
873 CONTEXT_ACTION(IMLIB_COLORMAP
,
874 imlib_context_set_colormap(context
->colormap
));
875 CONTEXT_ACTION(IMLIB_DRAWABLE
,
876 imlib_context_set_drawable(context
->drawable
));
877 CONTEXT_ACTION(IMLIB_MASK
,
878 imlib_context_set_mask(context
->mask
));
879 CONTEXT_ACTION(IMLIB_DITHER_MASK
,
880 imlib_context_set_dither_mask(context
->dither_mask
));
882 CONTEXT_ACTION(IMLIB_ANTI_ALIAS
,
883 imlib_context_set_anti_alias(context
->anti_alias
));
884 CONTEXT_ACTION(IMLIB_DITHER
,
885 imlib_context_set_dither(context
->dither
));
886 CONTEXT_ACTION(IMLIB_COLOR_MODIFIER
,
887 imlib_context_set_color_modifier(context
->color_modifier
));
888 CONTEXT_ACTION(IMLIB_DIRECTION
,
889 imlib_context_set_direction(context
->direction
));
890 CONTEXT_ACTION(IMLIB_ANGLE
,
891 imlib_context_set_angle(context
->angle
));
892 #undef CONTEXT_ACTION
894 /* This code should never be reached ! */
895 debug("Error restoring context!\n");
897 end_of_restore_context
:
898 vector_pop(contextes
);
900 contextes
=vector_free(contextes
);