Skip to content

Commit c6f3440

Browse files
committed
Get X background via Xlib, to remove flicker and obscuring issues
Currently, this does not work for non-image backgrounds, like when a color is set via icewmbg. Will then produce a black border.
1 parent d921343 commit c6f3440

File tree

9 files changed

+80
-141
lines changed

9 files changed

+80
-141
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ SRCDIR ?= src/
88
SHELL ?= /bin/sh
99
CC = g++
1010
CCFLAGS ?= -O2
11-
DEPS = $(shell pkg-config --libs --cflags glib-2.0 gtk+-3.0 libwnck-3.0 xcb-ewmh librsvg-2.0)
11+
DEPS = $(shell pkg-config --libs --cflags glib-2.0 gtk+-3.0 libwnck-3.0 xcb-ewmh librsvg-2.0 x11)
1212
ifneq (, $(shell which wx-config))
1313
DEPS += $(shell wx-config --cflags --libs)
1414
else

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Currently, simdock has to be compiled manually. The main dependencies are wxWidg
1919

2020
Under Void Linux:
2121

22-
sudo xbps-install pkg-config wxWidgets-gtk3-devel librsvg-devel xcb-ewmh libwnck-devel make gcc
22+
sudo xbps-install pkg-config wxWidgets-gtk3-devel librsvg-devel xcb-ewmh libwnck-devel libX11-devel make gcc
2323

2424
1. Type `make` to compile
2525
1. Type `sudo make install` to install

src/background.cc

+74-52
Original file line numberDiff line numberDiff line change
@@ -19,64 +19,86 @@
1919

2020
using namespace std;
2121

22+
// Function to fetch the root window background pixmap
23+
Pixmap getRootPixmap(Display* display, Window root) {
24+
Atom actual_type;
25+
int actual_format;
26+
unsigned long nitems, bytes_after;
27+
unsigned char* prop = nullptr;
28+
Atom prop_root = XInternAtom(display, "_XROOTPMAP_ID", True);
29+
30+
if (XGetWindowProperty(display, root, prop_root, 0, 1, False, XA_PIXMAP,
31+
&actual_type, &actual_format, &nitems, &bytes_after,
32+
&prop) == Success) {
33+
if (nitems == 1) {
34+
Pixmap pixmap = *(Pixmap*)prop;
35+
XFree(prop);
36+
return pixmap;
37+
}
38+
}
39+
return None;
40+
}
41+
42+
// Function to convert X11 Pixmap into wxImage
43+
wxImage ConvertPixmapToWxImage(Display* display, Pixmap pixmap, int width, int height) {
44+
XImage* ximage = XGetImage(display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap);
45+
if (!ximage) {
46+
std::cerr << "Failed to get XImage from Pixmap!" << std::endl;
47+
return wxImage(width, height);
48+
}
49+
50+
wxImage image(width, height);
51+
unsigned char* data = image.GetData();
52+
if (!data) {
53+
std::cerr << "Failed to allocate memory for wxImage data!" << std::endl;
54+
XDestroyImage(ximage);
55+
return wxImage(width, height);
56+
}
57+
58+
// Convert pixel data
59+
for (int y = 0; y < height; ++y) {
60+
for (int x = 0; x < width; ++x) {
61+
unsigned long pixel = XGetPixel(ximage, x, y);
62+
unsigned char red = (pixel >> 16) & 0xFF;
63+
unsigned char green = (pixel >> 8) & 0xFF;
64+
unsigned char blue = pixel & 0xFF;
65+
66+
data[(y * width + x) * 3 + 0] = red;
67+
data[(y * width + x) * 3 + 1] = green;
68+
data[(y * width + x) * 3 + 2] = blue;
69+
}
70+
}
71+
72+
XDestroyImage(ximage);
73+
return image;
74+
}
75+
2276
//get the currently used background
2377
wxBitmap* getRootWallpaper()
2478
{
25-
wxBitmap* backImage = new wxBitmap();
26-
WnckScreen *screen = wnck_screen_get_default ();
79+
wxBitmap* backImage;
80+
Display* display = XOpenDisplay(nullptr);
81+
if (!display) {
82+
std::cerr << "Unable to open X display" << std::endl;
83+
return NULL;
84+
}
2785

28-
// This is the X window ID of the desktop
29-
Pixmap pm = wnck_screen_get_background_pixmap(screen);
30-
int i = 0;
31-
while(i < 5)
32-
{
33-
if (pm != None) {
34-
break;
86+
Window root = DefaultRootWindow(display);
87+
88+
// Get the root window background pixmap
89+
Pixmap rootPixmap = getRootPixmap(display, root);
90+
if (rootPixmap != None) {
91+
int screen_width = DisplayWidth(display, DefaultScreen(display));
92+
int screen_height = DisplayHeight(display, DefaultScreen(display));
93+
94+
// Convert Pixmap to wxImage and then to wxBitmap
95+
wxImage image = ConvertPixmapToWxImage(display, rootPixmap, screen_width, screen_height);
96+
if (image.IsOk()) {
97+
backImage = new wxBitmap(image);
3598
}
36-
wxMilliSleep(1000);
37-
pm = wnck_screen_get_background_pixmap(screen);
38-
i++;
39-
}
40-
41-
if (pm != None) {
42-
wxSize sz = wxGetDisplaySize();
43-
// Note: This code to hide the app is duplicated with the outer call in tasks.cc, but this is needed for first app start
44-
wxGetApp().frame->SetTransparent(0);
45-
wxGetApp().frame->Hide();
46-
wxGetApp().frame->Disable();
47-
// Give the main UI thread a chance to hide the app first
48-
while(wxGetApp().frame->IsShown()) {
49-
wxMilliSleep(20);
50-
}
51-
// This sleep should be unnecessary, but without it the UI will not be hidden in the next step
52-
wxMilliSleep(20);
53-
wxBitmap* backImage = new wxBitmap(
54-
gdk_pixbuf_get_from_window(
55-
gdk_x11_window_foreign_new_for_display(
56-
gdk_display_get_default(),
57-
gdk_x11_get_default_root_xwindow()
58-
),
59-
0,
60-
0,
61-
sz.GetWidth(),
62-
sz.GetHeight()
63-
)
64-
);
65-
wxGetApp().frame->Show();
66-
wxGetApp().frame->SetTransparent(255);
67-
wxGetApp().frame->Enable();
68-
return backImage;
69-
} else {
70-
wxSize sz = wxGetDisplaySize();
71-
wxBitmap* backImage = new wxBitmap(sz.GetWidth(), sz.GetHeight());
72-
wxMemoryDC dc;
73-
dc.SelectObject(*backImage);
74-
dc.SetBackground(*wxTRANSPARENT_BRUSH);
75-
dc.Clear();
76-
dc.SelectObject(*backImage);
77-
return backImage;
7899
}
79-
return backImage;
100+
XCloseDisplay(display);
101+
return backImage;
80102
}
81103

82104
wxBitmap *fixImage (wxString url, int type, wxColour c)

src/background.h

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#define BACKGROUND_H_
2121

2222
#include "main.h"
23+
#include <X11/Xlib.h>
24+
#include <X11/Xatom.h>
2325

2426
wxBitmap *fixImage (wxString img, int type, wxColour c);
2527
wxBitmap* getRootWallpaper();

src/main.h

-10
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,6 @@ WX_DEFINE_ARRAY (simImage *, ImagesArray);
118118
#define NONE_STR "none"
119119
#define WALLPAPER_STR "wallpaper"
120120

121-
//#include <wx/arrimpl.cpp>
122-
//WX_DEFINE_OBJARRAY(simImage)
123-
//WX_DEFINE_OBJARRAY(ImagesList);
124-
125-
126-
//WX_DECLARE_LIST(simImage, ImagesList);
127-
128-
// the ID we'll use to identify our event
129-
//const int BACKGROUND_UPDATE_ID = 100000;
130-
131121

132122
/* wxString to std::string converter. Useful for printing stuff */
133123
std::string wx2std (const wxString & input);

src/myFrame.cc

-10
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,6 @@ EVT_MENU (ID_Keep, MyFrame::OnKeep)
6262
EVT_MENU (ID_Edit, MyFrame::OnEdit)
6363
EVT_MENU (ID_Delete, MyFrame::OnDelete)
6464
/*
65-
* Custom
66-
*/
67-
//EVT_COMMAND (BACKGROUND_UPDATE_ID, wxEVT_COMMAND_TEXT_UPDATED, MyFrame::OnDelayedBackground)
68-
/*
6965
* Painting
7066
*/
7167
EVT_PAINT (MyFrame::OnPaint)
@@ -250,12 +246,6 @@ MyFrame::GetWallpaper ()
250246
{
251247
return backImage;
252248
}
253-
254-
//void
255-
//MyFrame::OnDelayedBackground(wxCommandEvent &event) {
256-
//std::cout << "got update background event" << std::endl;
257-
//update_background();
258-
//}
259249

260250
void MyFrame::SetMarkBitmap (wxBitmap * newBmp)
261251
{

src/myFrame.h

-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ class MyFrame:public wxFrame
126126

127127
SettingsDialog *settingsDialog;
128128
void OnClose (wxCloseEvent &event);
129-
//void OnDelayedBackground(wxCommandEvent &event);
130129

131130
DECLARE_EVENT_TABLE ()
132131

src/tasks.cc

+2-65
Original file line numberDiff line numberDiff line change
@@ -207,78 +207,15 @@ bool check_overlap(int x1, int y1, int width1, int height1,
207207
return false;
208208
}
209209

210-
// Check whether our simdock window intersects with some different window
211-
bool is_covered(WnckScreen *screen) {
212-
GdkDisplay* display = gdk_display_get_default();
213-
GtkWidget* widget = wxGetApp().frame->GetHandle();
214-
GdkWindow* gdkWindow = gtk_widget_get_window(widget);
215-
XID xid = gdk_x11_window_get_xid(gdkWindow);
216-
WnckWindow* frameWindow = wnck_window_get(xid);
217-
218-
int win1_x, win1_y, win1_width, win1_height;
219-
wnck_window_get_geometry(frameWindow, &win1_x, &win1_y, &win1_width, &win1_height);
220-
221-
GList* allWindows = wnck_screen_get_windows(screen);
222-
for (GList *l = allWindows; l != NULL; l = l->next) {
223-
WnckWindow* curWindow = WNCK_WINDOW(l->data);
224-
if (wnck_window_is_visible_on_workspace(curWindow, wnck_screen_get_active_workspace(screen))) {
225-
Window otherXid = wnck_window_get_xid(curWindow);
226-
227-
// We use the XID here just to avoid confusion with different pointers
228-
if (xid != otherXid) {
229-
int win2_x, win2_y, win2_width, win2_height;
230-
wnck_window_get_geometry(curWindow, &win2_x, &win2_y, &win2_width, &win2_height);
231-
if (check_overlap(win1_x, win1_y, win1_width, win1_height, win2_x, win2_y, win2_width, win2_height)) {
232-
return true;
233-
}
234-
}
235-
}
236-
}
237-
return false;
238-
}
239-
240-
// Change the background for pseudo transparency mode
241-
void update_background() {
242-
std::cout << "updating background" << std::endl;
243-
// The signal arrives before the background is actually changed. The small sleep workarounds this issue.
244-
wxMilliSleep(20);
245-
// Now we hide the app, because getRootWallpaper() since the switch to GTK3 also sees simdock itself
246-
wxGetApp().frame->SetTransparent(0);
247-
wxGetApp().frame->Hide();
248-
wxGetApp().frame->Disable();
249-
wxGetApp().CallAfter([]{
250-
// The use of CallAfter is needed, otherwise the app won't be hidden while getRoootWallpaper runs
251-
wxBitmap* backImage = getRootWallpaper();
252-
wxGetApp().SetWallpaper(backImage);
253-
});
254-
}
255210

256211
void tasks_window_background_change (WnckScreen *screen, WnckWindow *window, callbackArgs* ca) {
257212
if (wxGetApp().frame->IsTransparentBackgroundSupported()) {
258213
// With real transparency enabled we have to do nothing here
259214
return;
260215
}
261216

262-
if (is_covered(screen)) {
263-
// Without real transparency, we don't want to continue if the frame is covered. It would
264-
// make us fetch the overlapping window as part of the background.
265-
std::thread([]() {
266-
WnckScreen* screen = wnck_screen_get_default();
267-
do {
268-
std::cout << "sleeping" << std::endl;
269-
std::this_thread::sleep_for(std::chrono::seconds(5)); // Delay of 5 seconds
270-
} while (is_covered(screen));
271-
std::cout << "send event" << std::endl;
272-
//wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, BACKGROUND_UPDATE_ID);
273-
//wxGetApp().frame->GetEventHandler()->AddPendingEvent(event);
274-
wxGetApp().CallAfter([]{
275-
update_background();
276-
});
277-
}).detach();
278-
return;
279-
}
280-
281-
update_background();
217+
wxBitmap* backImage = getRootWallpaper();
218+
wxGetApp().SetWallpaper(backImage);
282219
}
283220

284221
void tasks_track_active_window (WnckScreen *screen, WnckWindow *window, callbackArgs* ca) {

src/tasks.h

-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,5 @@ void tasks_register_signals(ImagesArray * ImagesList,simSettings settings);
6464
/* Adds a new image to the images list given a window and task informations */
6565
void tasks_addNewImage(WnckWindow *window, ImagesArray* ImagesList, simSettings settings,const taskInfo& ti);
6666
wxBitmap* tasks_getRootWallpaper();
67-
void update_background();
6867

6968
#endif

0 commit comments

Comments
 (0)